summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaligh Uddin <baligh@google.com>2013-11-01 16:01:19 -0700
committerBaligh Uddin <baligh@google.com>2013-11-01 16:01:19 -0700
commitda1db04101b57a1bad4b2f98f8898a0cf01f56e6 (patch)
treee8aef2dd2cb1fd57c4c2cde0ba837800fea259ad
parent4e2494aba4b4026751c5e2c08deae2178086c3da (diff)
parent5e667cc092b51bf91ee9f6562dc824a2c753d1e6 (diff)
downloadangle_dx11-idea133.tar.gz
Merge remote-tracking branch 'origin/kitkat-dev'idea133
-rw-r--r--.gitignore15
-rw-r--r--AUTHORS32
-rw-r--r--CONTRIBUTORS76
-rw-r--r--DEPS18
-rw-r--r--LICENSE32
-rw-r--r--README.chromium10
-rw-r--r--build/all.gyp27
-rw-r--r--build/common.gypi190
-rw-r--r--build/gyp_angle33
-rw-r--r--codereview.settings4
-rw-r--r--extensions/ANGLE_depth_texture.txt402
-rw-r--r--extensions/ANGLE_framebuffer_blit.txt437
-rw-r--r--extensions/ANGLE_framebuffer_multisample.txt363
-rw-r--r--extensions/ANGLE_instanced_arrays.txt359
-rw-r--r--extensions/ANGLE_pack_reverse_row_order.txt168
-rw-r--r--extensions/ANGLE_program_binary.txt94
-rw-r--r--extensions/ANGLE_texture_compression_dxt.txt163
-rw-r--r--extensions/ANGLE_texture_usage.txt202
-rw-r--r--extensions/ANGLE_timer_query.txt591
-rw-r--r--extensions/ANGLE_translated_shader_source.txt118
-rw-r--r--extensions/EGL_ANGLE_d3d_share_handle_client_buffer.txt98
-rw-r--r--extensions/EGL_ANGLE_direct3d_display.txt68
-rw-r--r--extensions/EGL_ANGLE_query_surface_pointer.txt88
-rw-r--r--extensions/EGL_ANGLE_software_display.txt65
-rw-r--r--extensions/EGL_ANGLE_surface_d3d_texture_2d_share_handle.txt95
-rw-r--r--extensions/EGL_EXT_create_context_robustness.txt169
-rw-r--r--extensions/EXT_draw_buffers.txt542
-rw-r--r--extensions/EXT_robustness.txt365
-rw-r--r--extensions/EXT_texture_storage.txt1090
-rw-r--r--include/EGL/egl.h329
-rw-r--r--include/EGL/eglext.h354
-rw-r--r--include/EGL/eglplatform.h129
-rw-r--r--include/GLES2/gl2.h621
-rw-r--r--include/GLES2/gl2ext.h1550
-rw-r--r--include/GLES2/gl2platform.h30
-rw-r--r--include/GLSLANG/ShaderLang.h446
-rw-r--r--include/KHR/khrplatform.h269
-rw-r--r--samples/angle/Simple_Instancing/Simple_Instancing.c230
-rw-r--r--samples/angle/Simple_Instancing/Simple_Instancing.vcxproj105
-rw-r--r--samples/build_samples.gyp178
-rw-r--r--samples/gles2_book/Common/Win32/esUtil_TGA.c122
-rw-r--r--samples/gles2_book/Common/Win32/esUtil_win32.c190
-rw-r--r--samples/gles2_book/Common/esShader.c155
-rw-r--r--samples/gles2_book/Common/esShapes.c279
-rw-r--r--samples/gles2_book/Common/esTransform.c212
-rw-r--r--samples/gles2_book/Common/esUtil.c290
-rw-r--r--samples/gles2_book/Common/esUtil.h297
-rw-r--r--samples/gles2_book/Common/esUtil.vcxproj103
-rw-r--r--samples/gles2_book/Common/esUtil.vcxproj.filters39
-rw-r--r--samples/gles2_book/Common/esUtil_win.h65
-rw-r--r--samples/gles2_book/Hello_Triangle/Hello_Triangle.c194
-rw-r--r--samples/gles2_book/Hello_Triangle/Hello_Triangle.vcxproj105
-rw-r--r--samples/gles2_book/MipMap2D/MipMap2D.c346
-rw-r--r--samples/gles2_book/MipMap2D/MipMap2D.vcxproj105
-rw-r--r--samples/gles2_book/MultiTexture/MultiTexture.c213
-rw-r--r--samples/gles2_book/MultiTexture/MultiTexture.vcxproj115
-rw-r--r--samples/gles2_book/MultiTexture/basemap.tgabin0 -> 786476 bytes
-rw-r--r--samples/gles2_book/MultiTexture/lightmap.tgabin0 -> 196626 bytes
-rw-r--r--samples/gles2_book/MultipleRenderTargets/MultipleRenderTargets.c295
-rw-r--r--samples/gles2_book/MultipleRenderTargets/MultipleRenderTargets.vcxproj105
-rw-r--r--samples/gles2_book/ParticleSystem/ParticleSystem.c294
-rw-r--r--samples/gles2_book/ParticleSystem/ParticleSystem.vcxproj111
-rw-r--r--samples/gles2_book/ParticleSystem/smoke.tgabin0 -> 49170 bytes
-rw-r--r--samples/gles2_book/PostSubBuffer/PostSubBuffer.c204
-rw-r--r--samples/gles2_book/PostSubBuffer/PostSubBuffer.vcxproj105
-rw-r--r--samples/gles2_book/Simple_Texture2D/Simple_Texture2D.c198
-rw-r--r--samples/gles2_book/Simple_Texture2D/Simple_Texture2D.vcxproj105
-rw-r--r--samples/gles2_book/Simple_TextureCubemap/Simple_TextureCubemap.c229
-rw-r--r--samples/gles2_book/Simple_TextureCubemap/Simple_TextureCubemap.vcxproj108
-rw-r--r--samples/gles2_book/Simple_VertexShader/Simple_VertexShader.c194
-rw-r--r--samples/gles2_book/Simple_VertexShader/Simple_VertexShader.vcxproj105
-rw-r--r--samples/gles2_book/Stencil_Test/Stencil_Test.c273
-rw-r--r--samples/gles2_book/Stencil_Test/Stencil_Test.vcxproj97
-rw-r--r--samples/gles2_book/TextureWrap/TextureWrap.c254
-rw-r--r--samples/gles2_book/TextureWrap/TextureWrap.vcxproj105
-rw-r--r--samples/samples.sln177
-rw-r--r--samples/translator/essl_to_glsl.vcproj193
-rw-r--r--samples/translator/essl_to_hlsl.vcxproj112
-rw-r--r--samples/translator/essl_to_hlsl.vcxproj.filters21
-rw-r--r--samples/translator/translator.cpp387
-rw-r--r--src/ANGLE.sln66
-rw-r--r--src/build_angle.gyp15
-rw-r--r--src/build_angle.gypi422
-rw-r--r--src/common/RefCountObject.cpp48
-rw-r--r--src/common/RefCountObject.h65
-rw-r--r--src/common/angleutils.h56
-rw-r--r--src/common/debug.cpp106
-rw-r--r--src/common/debug.h112
-rw-r--r--src/common/system.h26
-rw-r--r--src/common/version.h12
-rw-r--r--src/compiler/64bit-lexer-safety.patch177
-rw-r--r--src/compiler/BaseTypes.h148
-rw-r--r--src/compiler/BuiltInFunctionEmulator.cpp406
-rw-r--r--src/compiler/BuiltInFunctionEmulator.h93
-rw-r--r--src/compiler/CodeGenGLSL.cpp34
-rw-r--r--src/compiler/CodeGenHLSL.cpp33
-rw-r--r--src/compiler/Common.h77
-rw-r--r--src/compiler/Compiler.cpp408
-rw-r--r--src/compiler/ConstantUnion.h257
-rw-r--r--src/compiler/DetectCallDepth.cpp185
-rw-r--r--src/compiler/DetectCallDepth.h80
-rw-r--r--src/compiler/DetectDiscontinuity.cpp139
-rw-r--r--src/compiler/DetectDiscontinuity.h52
-rw-r--r--src/compiler/Diagnostics.cpp63
-rw-r--r--src/compiler/Diagnostics.h44
-rw-r--r--src/compiler/DirectiveHandler.cpp161
-rw-r--r--src/compiler/DirectiveHandler.h46
-rw-r--r--src/compiler/ExtensionBehavior.h37
-rw-r--r--src/compiler/ForLoopUnroll.cpp215
-rw-r--r--src/compiler/ForLoopUnroll.h48
-rw-r--r--src/compiler/HashNames.h19
-rw-r--r--src/compiler/InfoSink.cpp54
-rw-r--r--src/compiler/InfoSink.h115
-rw-r--r--src/compiler/Initialize.cpp564
-rw-r--r--src/compiler/Initialize.h23
-rw-r--r--src/compiler/InitializeDll.cpp32
-rw-r--r--src/compiler/InitializeDll.h13
-rw-r--r--src/compiler/InitializeGlobals.h13
-rw-r--r--src/compiler/InitializeParseContext.cpp40
-rw-r--r--src/compiler/InitializeParseContext.h17
-rw-r--r--src/compiler/IntermTraverse.cpp293
-rw-r--r--src/compiler/Intermediate.cpp1442
-rw-r--r--src/compiler/MMap.h56
-rw-r--r--src/compiler/MapLongVariableNames.cpp122
-rw-r--r--src/compiler/MapLongVariableNames.h59
-rw-r--r--src/compiler/OutputESSL.cpp26
-rw-r--r--src/compiler/OutputESSL.h25
-rw-r--r--src/compiler/OutputGLSL.cpp35
-rw-r--r--src/compiler/OutputGLSL.h26
-rw-r--r--src/compiler/OutputGLSLBase.cpp817
-rw-r--r--src/compiler/OutputGLSLBase.h79
-rw-r--r--src/compiler/OutputHLSL.cpp3094
-rw-r--r--src/compiler/OutputHLSL.h166
-rw-r--r--src/compiler/ParseHelper.cpp1600
-rw-r--r--src/compiler/ParseHelper.h134
-rw-r--r--src/compiler/PoolAlloc.cpp294
-rw-r--r--src/compiler/PoolAlloc.h300
-rw-r--r--src/compiler/Pragma.h19
-rw-r--r--src/compiler/QualifierAlive.cpp58
-rw-r--r--src/compiler/QualifierAlive.h7
-rw-r--r--src/compiler/RemoveTree.cpp77
-rw-r--r--src/compiler/RemoveTree.h7
-rw-r--r--src/compiler/RenameFunction.h36
-rw-r--r--src/compiler/SearchSymbol.cpp38
-rw-r--r--src/compiler/SearchSymbol.h33
-rw-r--r--src/compiler/ShHandle.h167
-rw-r--r--src/compiler/ShaderLang.cpp363
-rw-r--r--src/compiler/SymbolTable.cpp208
-rw-r--r--src/compiler/SymbolTable.h390
-rw-r--r--src/compiler/TranslatorESSL.cpp43
-rw-r--r--src/compiler/TranslatorESSL.h23
-rw-r--r--src/compiler/TranslatorGLSL.cpp44
-rw-r--r--src/compiler/TranslatorGLSL.h20
-rw-r--r--src/compiler/TranslatorHLSL.cpp24
-rw-r--r--src/compiler/TranslatorHLSL.h27
-rw-r--r--src/compiler/Types.h307
-rw-r--r--src/compiler/UnfoldShortCircuit.cpp176
-rw-r--r--src/compiler/UnfoldShortCircuit.h39
-rw-r--r--src/compiler/Uniform.cpp21
-rw-r--r--src/compiler/Uniform.h35
-rw-r--r--src/compiler/ValidateLimitations.cpp512
-rw-r--r--src/compiler/ValidateLimitations.h59
-rw-r--r--src/compiler/VariableInfo.cpp245
-rw-r--r--src/compiler/VariableInfo.h49
-rw-r--r--src/compiler/VariablePacker.cpp297
-rw-r--r--src/compiler/VariablePacker.h41
-rw-r--r--src/compiler/VersionGLSL.cpp140
-rw-r--r--src/compiler/VersionGLSL.h56
-rw-r--r--src/compiler/debug.cpp37
-rw-r--r--src/compiler/debug.h53
-rw-r--r--src/compiler/depgraph/DependencyGraph.cpp97
-rw-r--r--src/compiler/depgraph/DependencyGraph.h212
-rw-r--r--src/compiler/depgraph/DependencyGraphBuilder.cpp227
-rw-r--r--src/compiler/depgraph/DependencyGraphBuilder.h181
-rw-r--r--src/compiler/depgraph/DependencyGraphOutput.cpp65
-rw-r--r--src/compiler/depgraph/DependencyGraphOutput.h30
-rw-r--r--src/compiler/depgraph/DependencyGraphTraverse.cpp69
-rwxr-xr-xsrc/compiler/generate_parser.sh28
-rw-r--r--src/compiler/glslang.h16
-rw-r--r--src/compiler/glslang.l331
-rw-r--r--src/compiler/glslang.y2014
-rw-r--r--src/compiler/glslang_lex.cpp2940
-rw-r--r--src/compiler/glslang_tab.cpp4882
-rw-r--r--src/compiler/glslang_tab.h222
-rw-r--r--src/compiler/intermOut.cpp424
-rw-r--r--src/compiler/intermediate.h579
-rw-r--r--src/compiler/localintermediate.h57
-rw-r--r--src/compiler/osinclude.h65
-rw-r--r--src/compiler/ossource_posix.cpp64
-rw-r--r--src/compiler/ossource_win.cpp57
-rw-r--r--src/compiler/parseConst.cpp245
-rw-r--r--src/compiler/preprocessor/64bit-tokenizer-safety.patch159
-rw-r--r--src/compiler/preprocessor/DiagnosticsBase.cpp127
-rw-r--r--src/compiler/preprocessor/DiagnosticsBase.h87
-rw-r--r--src/compiler/preprocessor/DirectiveHandlerBase.cpp16
-rw-r--r--src/compiler/preprocessor/DirectiveHandlerBase.h43
-rw-r--r--src/compiler/preprocessor/DirectiveParser.cpp932
-rw-r--r--src/compiler/preprocessor/DirectiveParser.h82
-rw-r--r--src/compiler/preprocessor/ExpressionParser.cpp1981
-rw-r--r--src/compiler/preprocessor/ExpressionParser.h34
-rw-r--r--src/compiler/preprocessor/ExpressionParser.y285
-rw-r--r--src/compiler/preprocessor/Input.cpp54
-rw-r--r--src/compiler/preprocessor/Input.h49
-rw-r--r--src/compiler/preprocessor/Lexer.cpp16
-rw-r--r--src/compiler/preprocessor/Lexer.h25
-rw-r--r--src/compiler/preprocessor/Macro.cpp23
-rw-r--r--src/compiler/preprocessor/Macro.h44
-rw-r--r--src/compiler/preprocessor/MacroExpander.cpp370
-rw-r--r--src/compiler/preprocessor/MacroExpander.h75
-rw-r--r--src/compiler/preprocessor/Preprocessor.cpp142
-rw-r--r--src/compiler/preprocessor/Preprocessor.h51
-rw-r--r--src/compiler/preprocessor/SourceLocation.h38
-rw-r--r--src/compiler/preprocessor/Token.cpp83
-rw-r--r--src/compiler/preprocessor/Token.h106
-rw-r--r--src/compiler/preprocessor/Tokenizer.cpp2365
-rw-r--r--src/compiler/preprocessor/Tokenizer.h58
-rw-r--r--src/compiler/preprocessor/Tokenizer.l342
-rwxr-xr-xsrc/compiler/preprocessor/generate_parser.sh27
-rw-r--r--src/compiler/preprocessor/length_limits.h21
-rw-r--r--src/compiler/preprocessor/numeric_lex.h61
-rw-r--r--src/compiler/preprocessor/pp_utils.h18
-rw-r--r--src/compiler/preprocessor/preprocessor.vcxproj172
-rw-r--r--src/compiler/preprocessor/preprocessor.vcxproj.filters100
-rw-r--r--src/compiler/timing/RestrictFragmentShaderTiming.cpp127
-rw-r--r--src/compiler/timing/RestrictFragmentShaderTiming.h40
-rw-r--r--src/compiler/timing/RestrictVertexShaderTiming.cpp17
-rw-r--r--src/compiler/timing/RestrictVertexShaderTiming.h33
-rw-r--r--src/compiler/translator_common.vcxproj273
-rw-r--r--src/compiler/translator_common.vcxproj.filters271
-rw-r--r--src/compiler/translator_hlsl.vcxproj164
-rw-r--r--src/compiler/translator_hlsl.vcxproj.filters56
-rw-r--r--src/compiler/util.cpp33
-rw-r--r--src/compiler/util.h21
-rw-r--r--src/libEGL/Config.cpp340
-rw-r--r--src/libEGL/Config.h115
-rw-r--r--src/libEGL/Display.cpp537
-rw-r--r--src/libEGL/Display.h94
-rw-r--r--src/libEGL/Surface.cpp408
-rw-r--r--src/libEGL/Surface.h108
-rw-r--r--src/libEGL/libEGL.cpp1188
-rw-r--r--src/libEGL/libEGL.def36
-rw-r--r--src/libEGL/libEGL.rc102
-rw-r--r--src/libEGL/libEGL.vcxproj258
-rw-r--r--src/libEGL/libEGL.vcxproj.filters68
-rw-r--r--src/libEGL/main.cpp166
-rw-r--r--src/libEGL/main.h62
-rw-r--r--src/libEGL/resource.h14
-rw-r--r--src/libGLESv2/BinaryStream.h164
-rw-r--r--src/libGLESv2/Buffer.cpp126
-rw-r--r--src/libGLESv2/Buffer.h68
-rw-r--r--src/libGLESv2/Context.cpp2972
-rw-r--r--src/libGLESv2/Context.h505
-rw-r--r--src/libGLESv2/Fence.cpp52
-rw-r--r--src/libGLESv2/Fence.h43
-rw-r--r--src/libGLESv2/Float16ToFloat32.cpp2204
-rw-r--r--src/libGLESv2/Float16ToFloat32.py78
-rw-r--r--src/libGLESv2/Framebuffer.cpp603
-rw-r--r--src/libGLESv2/Framebuffer.h108
-rw-r--r--src/libGLESv2/HandleAllocator.cpp64
-rw-r--r--src/libGLESv2/HandleAllocator.h45
-rw-r--r--src/libGLESv2/Program.cpp525
-rw-r--r--src/libGLESv2/Program.h130
-rw-r--r--src/libGLESv2/ProgramBinary.cpp2620
-rw-r--r--src/libGLESv2/ProgramBinary.h174
-rw-r--r--src/libGLESv2/Query.cpp52
-rw-r--r--src/libGLESv2/Query.h49
-rw-r--r--src/libGLESv2/Renderbuffer.cpp485
-rw-r--r--src/libGLESv2/Renderbuffer.h261
-rw-r--r--src/libGLESv2/ResourceManager.cpp322
-rw-r--r--src/libGLESv2/ResourceManager.h108
-rw-r--r--src/libGLESv2/Shader.cpp622
-rw-r--r--src/libGLESv2/Shader.h184
-rw-r--r--src/libGLESv2/Texture.cpp1495
-rw-r--r--src/libGLESv2/Texture.h275
-rw-r--r--src/libGLESv2/Uniform.cpp43
-rw-r--r--src/libGLESv2/Uniform.h48
-rw-r--r--src/libGLESv2/angletypes.h129
-rw-r--r--src/libGLESv2/constants.h34
-rw-r--r--src/libGLESv2/libGLESv2.cpp7106
-rw-r--r--src/libGLESv2/libGLESv2.def185
-rw-r--r--src/libGLESv2/libGLESv2.rc102
-rw-r--r--src/libGLESv2/libGLESv2.vcxproj425
-rw-r--r--src/libGLESv2/libGLESv2.vcxproj.filters515
-rw-r--r--src/libGLESv2/main.cpp155
-rw-r--r--src/libGLESv2/main.h68
-rw-r--r--src/libGLESv2/mathutil.h161
-rw-r--r--src/libGLESv2/precompiled.cpp9
-rw-r--r--src/libGLESv2/precompiled.h42
-rw-r--r--src/libGLESv2/renderer/Blit.cpp595
-rw-r--r--src/libGLESv2/renderer/Blit.h94
-rw-r--r--src/libGLESv2/renderer/BufferStorage.cpp40
-rw-r--r--src/libGLESv2/renderer/BufferStorage.h44
-rw-r--r--src/libGLESv2/renderer/BufferStorage11.cpp358
-rw-r--r--src/libGLESv2/renderer/BufferStorage11.h56
-rw-r--r--src/libGLESv2/renderer/BufferStorage9.cpp78
-rw-r--r--src/libGLESv2/renderer/BufferStorage9.h42
-rw-r--r--src/libGLESv2/renderer/Fence11.cpp134
-rw-r--r--src/libGLESv2/renderer/Fence11.h39
-rw-r--r--src/libGLESv2/renderer/Fence9.cpp135
-rw-r--r--src/libGLESv2/renderer/Fence9.h39
-rw-r--r--src/libGLESv2/renderer/FenceImpl.h45
-rw-r--r--src/libGLESv2/renderer/Image.cpp548
-rw-r--r--src/libGLESv2/renderer/Image.h131
-rw-r--r--src/libGLESv2/renderer/Image11.cpp457
-rw-r--r--src/libGLESv2/renderer/Image11.h76
-rw-r--r--src/libGLESv2/renderer/Image9.cpp732
-rw-r--r--src/libGLESv2/renderer/Image9.h79
-rw-r--r--src/libGLESv2/renderer/ImageSSE2.cpp100
-rw-r--r--src/libGLESv2/renderer/IndexBuffer.cpp185
-rw-r--r--src/libGLESv2/renderer/IndexBuffer.h111
-rw-r--r--src/libGLESv2/renderer/IndexBuffer11.cpp182
-rw-r--r--src/libGLESv2/renderer/IndexBuffer11.h53
-rw-r--r--src/libGLESv2/renderer/IndexBuffer9.cpp207
-rw-r--r--src/libGLESv2/renderer/IndexBuffer9.h53
-rw-r--r--src/libGLESv2/renderer/IndexDataManager.cpp314
-rw-r--r--src/libGLESv2/renderer/IndexDataManager.h66
-rw-r--r--src/libGLESv2/renderer/IndexRangeCache.cpp97
-rw-r--r--src/libGLESv2/renderer/IndexRangeCache.h58
-rw-r--r--src/libGLESv2/renderer/InputLayoutCache.cpp202
-rw-r--r--src/libGLESv2/renderer/InputLayoutCache.h80
-rw-r--r--src/libGLESv2/renderer/Query11.cpp122
-rw-r--r--src/libGLESv2/renderer/Query11.h40
-rw-r--r--src/libGLESv2/renderer/Query9.cpp125
-rw-r--r--src/libGLESv2/renderer/Query9.h40
-rw-r--r--src/libGLESv2/renderer/QueryImpl.h42
-rw-r--r--src/libGLESv2/renderer/RenderStateCache.cpp406
-rw-r--r--src/libGLESv2/renderer/RenderStateCache.h101
-rw-r--r--src/libGLESv2/renderer/RenderTarget.h56
-rw-r--r--src/libGLESv2/renderer/RenderTarget11.cpp355
-rw-r--r--src/libGLESv2/renderer/RenderTarget11.h51
-rw-r--r--src/libGLESv2/renderer/RenderTarget9.cpp113
-rw-r--r--src/libGLESv2/renderer/RenderTarget9.h40
-rw-r--r--src/libGLESv2/renderer/Renderer.cpp220
-rw-r--r--src/libGLESv2/renderer/Renderer.h244
-rw-r--r--src/libGLESv2/renderer/Renderer11.cpp3535
-rw-r--r--src/libGLESv2/renderer/Renderer11.h358
-rw-r--r--src/libGLESv2/renderer/Renderer9.cpp3222
-rw-r--r--src/libGLESv2/renderer/Renderer9.h349
-rw-r--r--src/libGLESv2/renderer/ShaderCache.h110
-rw-r--r--src/libGLESv2/renderer/ShaderExecutable.h51
-rw-r--r--src/libGLESv2/renderer/ShaderExecutable11.cpp109
-rw-r--r--src/libGLESv2/renderer/ShaderExecutable11.h47
-rw-r--r--src/libGLESv2/renderer/ShaderExecutable9.cpp60
-rw-r--r--src/libGLESv2/renderer/ShaderExecutable9.h39
-rw-r--r--src/libGLESv2/renderer/SwapChain.h44
-rw-r--r--src/libGLESv2/renderer/SwapChain11.cpp767
-rw-r--r--src/libGLESv2/renderer/SwapChain11.h78
-rw-r--r--src/libGLESv2/renderer/SwapChain9.cpp434
-rw-r--r--src/libGLESv2/renderer/SwapChain9.h55
-rw-r--r--src/libGLESv2/renderer/TextureStorage.cpp122
-rw-r--r--src/libGLESv2/renderer/TextureStorage.h110
-rw-r--r--src/libGLESv2/renderer/TextureStorage11.cpp667
-rw-r--r--src/libGLESv2/renderer/TextureStorage11.h120
-rw-r--r--src/libGLESv2/renderer/TextureStorage9.cpp328
-rw-r--r--src/libGLESv2/renderer/TextureStorage9.h109
-rw-r--r--src/libGLESv2/renderer/VertexBuffer.cpp245
-rw-r--r--src/libGLESv2/renderer/VertexBuffer.h138
-rw-r--r--src/libGLESv2/renderer/VertexBuffer11.cpp418
-rw-r--r--src/libGLESv2/renderer/VertexBuffer11.h73
-rw-r--r--src/libGLESv2/renderer/VertexBuffer9.cpp486
-rw-r--r--src/libGLESv2/renderer/VertexBuffer9.h90
-rw-r--r--src/libGLESv2/renderer/VertexDataManager.cpp267
-rw-r--r--src/libGLESv2/renderer/VertexDataManager.h65
-rw-r--r--src/libGLESv2/renderer/VertexDeclarationCache.cpp217
-rw-r--r--src/libGLESv2/renderer/VertexDeclarationCache.h58
-rw-r--r--src/libGLESv2/renderer/generatemip.h203
-rw-r--r--src/libGLESv2/renderer/renderer11_utils.cpp688
-rw-r--r--src/libGLESv2/renderer/renderer11_utils.h95
-rw-r--r--src/libGLESv2/renderer/renderer9_utils.cpp500
-rw-r--r--src/libGLESv2/renderer/renderer9_utils.h74
-rw-r--r--src/libGLESv2/renderer/shaders/Blit.ps39
-rw-r--r--src/libGLESv2/renderer/shaders/Blit.vs43
-rw-r--r--src/libGLESv2/renderer/shaders/Clear11.hlsl38
-rw-r--r--src/libGLESv2/renderer/shaders/Passthrough11.hlsl29
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/clear11vs.h133
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/clearmultiple11ps.h199
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/clearsingle11ps.h113
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/componentmaskps.h81
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/flipyvs.h69
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/luminanceps.h80
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/passthrough11vs.h137
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/passthroughlum11ps.h155
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/passthroughlumalpha11ps.h151
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/passthroughps.h63
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/passthroughrgb11ps.h155
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/passthroughrgba11ps.h144
-rw-r--r--src/libGLESv2/renderer/shaders/compiled/standardvs.h69
-rw-r--r--src/libGLESv2/renderer/shaders/generate_shaders.bat24
-rw-r--r--src/libGLESv2/renderer/vertexconversion.h203
-rw-r--r--src/libGLESv2/resource.h14
-rw-r--r--src/libGLESv2/utilities.cpp769
-rw-r--r--src/libGLESv2/utilities.h67
-rw-r--r--src/preprocessor.target.darwin-arm.mk272
-rw-r--r--src/preprocessor.target.darwin-mips.mk268
-rw-r--r--src/preprocessor.target.darwin-x86.mk272
-rw-r--r--src/preprocessor.target.linux-arm.mk272
-rw-r--r--src/preprocessor.target.linux-mips.mk268
-rw-r--r--src/preprocessor.target.linux-x86.mk272
-rw-r--r--src/third_party/compiler/ArrayBoundsClamper.cpp106
-rw-r--r--src/third_party/compiler/ArrayBoundsClamper.h62
-rw-r--r--src/third_party/compiler/LICENSE22
-rw-r--r--src/third_party/compiler/README.angle12
-rw-r--r--src/third_party/murmurhash/LICENSE2
-rw-r--r--src/third_party/murmurhash/MurmurHash3.cpp334
-rw-r--r--src/third_party/murmurhash/MurmurHash3.h37
-rw-r--r--src/translator_common.target.darwin-arm.mk303
-rw-r--r--src/translator_common.target.darwin-mips.mk299
-rw-r--r--src/translator_common.target.darwin-x86.mk303
-rw-r--r--src/translator_common.target.linux-arm.mk303
-rw-r--r--src/translator_common.target.linux-mips.mk299
-rw-r--r--src/translator_common.target.linux-x86.mk303
-rw-r--r--src/translator_glsl.target.darwin-arm.mk275
-rw-r--r--src/translator_glsl.target.darwin-mips.mk271
-rw-r--r--src/translator_glsl.target.darwin-x86.mk275
-rw-r--r--src/translator_glsl.target.linux-arm.mk275
-rw-r--r--src/translator_glsl.target.linux-mips.mk271
-rw-r--r--src/translator_glsl.target.linux-x86.mk275
-rw-r--r--tests/build_tests.gyp93
-rw-r--r--tests/compiler_tests/ExpressionLimit_test.cpp512
-rw-r--r--tests/compiler_tests/VariablePacker_test.cpp85
-rw-r--r--tests/preprocessor_tests/MockDiagnostics.h20
-rw-r--r--tests/preprocessor_tests/MockDirectiveHandler.h33
-rw-r--r--tests/preprocessor_tests/PreprocessorTest.cpp29
-rw-r--r--tests/preprocessor_tests/PreprocessorTest.h30
-rw-r--r--tests/preprocessor_tests/char_test.cpp98
-rw-r--r--tests/preprocessor_tests/comment_test.cpp69
-rw-r--r--tests/preprocessor_tests/define_test.cpp893
-rw-r--r--tests/preprocessor_tests/error_test.cpp92
-rw-r--r--tests/preprocessor_tests/extension_test.cpp103
-rw-r--r--tests/preprocessor_tests/identifier_test.cpp162
-rw-r--r--tests/preprocessor_tests/if_test.cpp835
-rw-r--r--tests/preprocessor_tests/input_test.cpp161
-rw-r--r--tests/preprocessor_tests/location_test.cpp303
-rw-r--r--tests/preprocessor_tests/number_test.cpp170
-rw-r--r--tests/preprocessor_tests/operator_test.cpp80
-rw-r--r--tests/preprocessor_tests/pragma_test.cpp126
-rw-r--r--tests/preprocessor_tests/space_test.cpp106
-rw-r--r--tests/preprocessor_tests/token_test.cpp90
-rw-r--r--tests/preprocessor_tests/version_test.cpp229
439 files changed, 116536 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..da50cf1b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+Debug
+Release
+*.sdf
+*.ncb
+*.suo
+*.vcproj.*
+*.vcxproj.user
+patches-*
+*.target.mk
+ipch
+debug.txt
+*.opensdf
+*.orig
+*.rej
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..a2ce9157
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,32 @@
+# This is the official list of The ANGLE Project Authors
+# for copyright purposes.
+# This file is distinct from the CONTRIBUTORS files.
+# See the latter for an explanation.
+
+# Names should be added to this file as
+# Name or Organization
+# Email addresses for individuals are tracked elsewhere to avoid spam.
+
+Google Inc.
+TransGaming Inc.
+3DLabs Inc. Ltd.
+
+Adobe Systems Inc.
+Autodesk, Inc.
+Cloud Party, Inc.
+Intel Corporation
+Mozilla Corporation
+Turbulenz
+Klarälvdalens Datakonsult AB
+
+Jacek Caban
+Mark Callow
+Ginn Chen
+James Hauxwell
+Sam Hocevar
+Pierre Leveille
+Jonathan Liu
+Boying Lu
+Aitor Moreno
+Yuri O'Donnell
+Josh Soref
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
index 00000000..00ebe7cf
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,76 @@
+# This is the official list of people who can contribute
+# (and who have contributed) code to the ANGLE project
+# repository.
+# The AUTHORS file lists the copyright holders; this file
+# lists people. For example, Google employees are listed here
+# but not in AUTHORS, because Google holds the copyright.
+#
+
+TransGaming Inc.
+ Nicolas Capens
+ Daniel Koch
+ Geoff Lang
+ Andrew Lewycky
+ Jamie Madill
+ Gavriel State
+ Shannon Woods
+
+Google Inc.
+ Brent Austin
+ Michael Bai
+ John Bauman
+ Peter Beverloo
+ Steve Block
+ Rachel Blum
+ Eric Boren
+ Henry Bridge
+ Nat Duca
+ Peter Kasting
+ Vangelis Kokkevis
+ Zhenyao Mo
+ Daniel Nicoara
+ Alastair Patrick
+ Alok Priyadarshi
+ Kenneth Russell
+ Brian Salomon
+ Gregg Tavares
+ Jeff Timanus
+ Ben Vanik
+ Adrienne Walker
+ thestig@chromium.org
+ Justin Schuh
+
+Adobe Systems Inc.
+ Alexandru Chiculita
+ Steve Minns
+ Max Vujovic
+
+Autodesk, Inc.
+ Ranger Harke
+
+Cloud Party, Inc.
+ Conor Dickinson
+
+Intel Corporation
+ Jin Yang
+ Andy Chen
+ Josh Triplett
+
+Klarälvdalens Datakonsult AB
+ Milian Wolff
+
+Mozilla Corp.
+ Ehsan Akhgari
+ Jeff Gilbert
+ Mike Hommey
+ Benoit Jacob
+ Makoto Kato
+ Vladimir Vukicevic
+
+Turbulenz
+ Michael Braithwaite
+
+Ulrik Persson (ddefrostt)
+Mark Banner (standard8mbp)
+David Kilzer
+
diff --git a/DEPS b/DEPS
new file mode 100644
index 00000000..1e5112c8
--- /dev/null
+++ b/DEPS
@@ -0,0 +1,18 @@
+deps = {
+ "trunk/third_party/gyp":
+ "http://gyp.googlecode.com/svn/trunk@1564",
+
+ "trunk/third_party/googletest":
+ "http://googletest.googlecode.com/svn/trunk@573", #release 1.6.0
+
+ "trunk/third_party/googlemock":
+ "http://googlemock.googlecode.com/svn/trunk@387", #release 1.6.0
+}
+
+hooks = [
+ {
+ # A change to a .gyp, .gypi, or to GYP itself should run the generator.
+ "pattern": ".",
+ "action": ["python", "trunk/build/gyp_angle"],
+ },
+]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..bdacb32e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,32 @@
+// Copyright (C) 2002-2013 The ANGLE Project Authors.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc.
+// Ltd., nor the names of their contributors may be used to endorse
+// or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.chromium b/README.chromium
new file mode 100644
index 00000000..b141fb53
--- /dev/null
+++ b/README.chromium
@@ -0,0 +1,10 @@
+Name: ANGLE
+URL: https://code.google.com/p/angleproject/
+Version: 2422
+License: BSD
+License File: LICENSE
+
+Description:
+ANGLE is a conformant implementation of the OpenGL ES 2.0
+specification that is hardware‐accelerated via Direct3D.
+
diff --git a/build/all.gyp b/build/all.gyp
new file mode 100644
index 00000000..fff99987
--- /dev/null
+++ b/build/all.gyp
@@ -0,0 +1,27 @@
+# Copyright (c) 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'all',
+ 'type': 'none',
+ 'dependencies': [
+ # TODO(alokp): build_ prefix should be removed from the gyp files
+ # as soon as we can get rid of manually-maintained sln files.
+ # Otherwise auto-generated sln files will overwrite/conflict the
+ # manually maintained ones.
+ '../samples/build_samples.gyp:*',
+ '../src/build_angle.gyp:*',
+ '../tests/build_tests.gyp:*',
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/build/common.gypi b/build/common.gypi
new file mode 100644
index 00000000..fc9f2951
--- /dev/null
+++ b/build/common.gypi
@@ -0,0 +1,190 @@
+# Copyright (c) 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.
+
+{
+ 'variables': {
+ 'component%': 'static_library',
+ # angle_code is set to 1 for the core ANGLE targets defined in src/build_angle.gyp.
+ # angle_code is set to 0 for test code, sample code, and third party code.
+ # When angle_code is 1, we build with additional warning flags on Mac and Linux.
+ 'angle_code%': 0,
+ 'gcc_or_clang_warnings': [
+ '-Wall',
+ '-Wchar-subscripts',
+ '-Werror',
+ '-Wextra',
+ '-Wformat=2',
+ '-Winit-self',
+ '-Wno-sign-compare',
+ '-Wno-unused-function',
+ '-Wno-unused-parameter',
+ '-Wno-unknown-pragmas',
+ '-Wpacked',
+ '-Wpointer-arith',
+ '-Wundef',
+ '-Wwrite-strings',
+ ],
+ },
+ 'target_defaults': {
+ 'default_configuration': 'Debug',
+ 'variables': {
+ 'warn_as_error%': 1,
+ },
+ 'target_conditions': [
+ ['warn_as_error == 1', {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WarnAsError': 'true',
+ },
+ },
+ }],
+ ],
+ 'configurations': {
+ 'Common': {
+ 'abstract': 1,
+ 'msvs_configuration_attributes': {
+ 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)',
+ 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)',
+ 'CharacterSet': '1', # UNICODE
+ },
+ 'msvs_configuration_platform': 'Win32',
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'BufferSecurityCheck': 'true',
+ 'DebugInformationFormat': '3',
+ # TODO(alokp): Disable exceptions before integrating with chromium.
+ #'ExceptionHandling': '0',
+ 'EnableFunctionLevelLinking': 'true',
+ 'MinimalRebuild': 'false',
+ 'PreprocessorDefinitions': [
+ '_CRT_SECURE_NO_DEPRECATE',
+ '_HAS_EXCEPTIONS=0',
+ '_WIN32_WINNT=0x0600',
+ '_WINDOWS',
+ 'NOMINMAX',
+ 'WIN32',
+ 'WIN32_LEAN_AND_MEAN',
+ 'WINVER=0x0600',
+ ],
+ 'RuntimeTypeInfo': 'false',
+ 'WarningLevel': '4',
+ 'DisableSpecificWarnings': [4100, 4127, 4189, 4239, 4244, 4245, 4512, 4702],
+ },
+ 'VCLinkerTool': {
+ 'FixedBaseAddress': '1',
+ 'GenerateDebugInformation': 'true',
+ 'ImportLibrary': '$(OutDir)\\lib\\$(TargetName).lib',
+ 'MapFileName': '$(OutDir)\\$(TargetName).map',
+ # Most of the executables we'll ever create are tests
+ # and utilities with console output.
+ 'SubSystem': '1', # /SUBSYSTEM:CONSOLE
+ 'AdditionalLibraryDirectories': [
+ '$(ProgramFiles)/Windows Kits/8.0/Lib/win8/um/x86',
+ ],
+ },
+ 'VCLibrarianTool': {
+ 'AdditionalLibraryDirectories': [
+ '$(ProgramFiles)/Windows Kits/8.0/Lib/win8/um/x86',
+ ],
+ },
+ 'VCResourceCompilerTool': {
+ 'Culture': '1033',
+ },
+ },
+ 'msvs_system_include_dirs': [
+ '$(ProgramFiles)/Windows Kits/8.0/Include/shared',
+ '$(ProgramFiles)/Windows Kits/8.0/Include/um',
+ ],
+ }, # Common
+ 'Debug': {
+ 'inherit_from': ['Common'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'Optimization': '0', # /Od
+ 'PreprocessorDefinitions': ['_DEBUG'],
+ 'BasicRuntimeChecks': '3',
+ 'RuntimeLibrary': '1', # /MTd (debug static)
+ },
+ 'VCLinkerTool': {
+ 'LinkIncremental': '2',
+ },
+ },
+ 'xcode_settings': {
+ 'COPY_PHASE_STRIP': 'NO',
+ 'GCC_OPTIMIZATION_LEVEL': '0',
+ },
+ }, # Debug
+ 'Release': {
+ 'inherit_from': ['Common'],
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'Optimization': '2', # /Os
+ 'PreprocessorDefinitions': ['NDEBUG'],
+ 'RuntimeLibrary': '0', # /MT (static)
+ },
+ 'VCLinkerTool': {
+ 'LinkIncremental': '1',
+ },
+ },
+ }, # Release
+ }, # configurations
+ 'conditions': [
+ ['component=="shared_library"', {
+ 'defines': ['COMPONENT_BUILD'],
+ }],
+ ],
+ }, # target_defaults
+ 'conditions': [
+ ['OS=="win"', {
+ 'target_defaults': {
+ 'msvs_cygwin_dirs': ['../third_party/cygwin'],
+ },
+ }],
+ ['OS!="win" and OS!="mac"', {
+ 'target_defaults': {
+ 'cflags': [
+ '-pthread',
+ '-fno-exceptions',
+ ],
+ 'ldflags': [
+ '-pthread',
+ ],
+ 'configurations': {
+ 'Debug': {
+ 'variables': {
+ 'debug_optimize%': '0',
+ },
+ 'defines': [
+ '_DEBUG',
+ ],
+ 'cflags': [
+ '-O>(debug_optimize)',
+ '-g',
+ ],
+ }
+ },
+ },
+ }],
+ ['angle_code==1', {
+ 'target_defaults': {
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'WARNING_CFLAGS': ['<@(gcc_or_clang_warnings)']
+ },
+ }],
+ ['OS!="win" and OS!="mac"', {
+ 'cflags': ['<@(gcc_or_clang_warnings)']
+ }],
+ ]
+ }
+ }],
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/build/gyp_angle b/build/gyp_angle
new file mode 100644
index 00000000..2aa38a52
--- /dev/null
+++ b/build/gyp_angle
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+
+# Copyright (c) 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.
+
+# This script is wrapper for ANGLE that adds some support for how GYP
+# is invoked by ANGLE beyond what can be done in the gclient hooks.
+
+import os
+import sys
+
+script_dir = os.path.dirname(__file__)
+angle_dir = os.path.normpath(os.path.join(script_dir, os.pardir))
+
+sys.path.append(os.path.join(angle_dir, 'third_party', 'gyp', 'pylib'))
+import gyp
+
+if __name__ == '__main__':
+ args = sys.argv[1:]
+
+ print 'Updating projects from gyp files...'
+ sys.stdout.flush()
+
+ # Set the depth to get the top-level Makefile generated into the
+ # correct directory. This only has an effect on Linux.
+ args.append('--depth');
+ args.append('./trunk');
+ # Add common.gypi to the include path.
+ args.append('-I' + os.path.join(script_dir, 'common.gypi'))
+ # Add all.gyp as the main gyp file to be generated.
+ args.append(os.path.join(script_dir, 'all.gyp'))
+ sys.exit(gyp.main(args))
diff --git a/codereview.settings b/codereview.settings
new file mode 100644
index 00000000..de224f34
--- /dev/null
+++ b/codereview.settings
@@ -0,0 +1,4 @@
+# This file is used by gcl to get repository specific information.
+CODE_REVIEW_SERVER: codereview.appspot.com
+CC_LIST: angleproject-review@googlegroups.com
+VIEW_VC: http://code.google.com/p/angleproject/source/detail?r=
diff --git a/extensions/ANGLE_depth_texture.txt b/extensions/ANGLE_depth_texture.txt
new file mode 100644
index 00000000..067ecc5e
--- /dev/null
+++ b/extensions/ANGLE_depth_texture.txt
@@ -0,0 +1,402 @@
+Name
+
+ ANGLE_depth_texture
+
+Name Strings
+
+ GL_ANGLE_depth_texture
+
+Contributors
+
+ Nicolas Capens, TransGaming
+ Daniel Koch, TransGaming
+ Shannon Woods, TransGaming
+ Kenneth Russell, Google
+ Vangelis Kokkevis, Google
+ Gregg Tavares, Google
+ Contributors to OES_depth_texture
+ Contributors to OES_packed_depth_stencil
+
+Contact
+
+ Shannon Woods, TransGaming (shannon 'dot' woods 'at' transgaming.com)
+
+Status
+
+ Implemented in ANGLE.
+
+Version
+
+ Last Modified Date: February 25, 2013
+ Revision: #4
+
+Number
+
+ TBD
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+ This extension is written against the OpenGL ES 2.0.25 specification
+
+ OES_packed_depth_stencil affects the definition of this extension.
+
+ EXT_texture_storage affects the definition of this extension.
+
+Overview
+
+ This extension defines support for 2D depth and depth-stencil
+ textures in an OpenGL ES implementation.
+
+ This extension incorporates the depth texturing functionality of
+ OES_depth_texture and OES_packed_depth_stencil, but does not
+ provide the ability to load existing data via TexImage2D or
+ TexSubImage2D. This extension also allows implementation
+ variability in which components from a sampled depth texture
+ contain the depth data. Depth textures created with this
+ extension only support 1 level.
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ Accepted by the <format> parameter of TexImage2D and TexSubImage2D and
+ <internalformat> parameter of TexImage2D:
+
+ DEPTH_COMPONENT 0x1902
+ DEPTH_STENCIL_OES 0x84F9
+
+ Accepted by the <type> parameter of TexImage2D, TexSubImage2D:
+
+ UNSIGNED_SHORT 0x1403
+ UNSIGNED_INT 0x1405
+ UNSIGNED_INT_24_8_OES 0x84FA
+
+ Accepted by the <internalformat> parameter of TexStorage2DEXT:
+
+ DEPTH_COMPONENT16 0x81A5
+ DEPTH_COMPONENT32_OES 0x81A7
+ DEPTH24_STENCIL8_OES 0x88F0
+
+Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL Operation)
+
+ Update Section 2.10.5 "Shader Execution" in the subsection titled
+ "Texture Access" add a new paragraph before the last paragraph add
+ this line:
+
+ "The stencil index texture internal component is ignored if the base
+ internal format is DEPTH_STENCIL_OES.
+
+ If a vertex shader uses..."
+
+Additions to Chapter 3 of the OpenGL ES 2.0 specification (Rasterization)
+
+ Add the following rows to Table 3.2 (page 62):
+
+ type Parameter GL Data Type Special
+ ------------------------------------------------
+ ... ... ...
+ UNSIGNED_SHORT ushort No
+ UNSIGNED_INT uint No
+ UNSIGNED_INT_24_8_OES uint Yes
+
+ Add the following rows to Table 3.3 (page 62):
+
+ Format Name Element Meaning and Order Target Buffer
+ ------------------------------------------------------------------
+ ... ... ...
+ DEPTH_COMPONENT Depth Depth
+ DEPTH_STENCIL_OES Depth and Stencil Index Depth and Stencil
+ ... ... ...
+
+ Add a row to Table 3.5 "Packed pixel formats" (page 64):
+
+ type Parameter GL Type Components Pixel Formats
+ ------------------------------------------------------------------
+ ... ... ... ...
+ UNSIGNED_INT_24_8_OES uint 2 DEPTH_STENCIL_OES
+
+ Add a new table after Table 3.6 (page 64):
+
+ UNSIGNED_INT_24_8_OES
+
+ 31 30 29 28 27 26 ... 12 11 10 9 8 7 6 5 4 3 2 1 0
+ +----------------------------------+---------------+
+ | 1st Component | 2nd Component |
+ +----------------------------------+---------------+
+
+ Table 3.6.B: UNSIGNED_INT formats
+
+ Add a row to Table 3.7 "Packed pixel field assignments" (page 65):
+
+ Format | 1st 2nd 3rd 4th
+ ------------------+-------------------------------
+ ... | ... ... ... ...
+ DEPTH_STENCIL_OES | depth stencil N/A N/A
+
+ Add the following paragraph to the end of the section "Conversion to
+ floating-point" (page 65):
+
+ "For groups of components that contain both standard components and index
+ elements, such as DEPTH_STENCIL_OES, the index elements are not converted."
+
+ In section 3.7.1 "Texture Image Specification", update page 67 to
+ say:
+
+ "The selected groups are processed as described in section 3.6.2, stopping
+ just before final conversion. Each R, G, B, A, or depth value so generated
+ is clamped to [0, 1], while the stencil index values are masked by 2^n-1,
+ where n is the number of stencil bits in the internal format resolution
+ (see below).
+
+ Components are then selected from the resulting R, G, B, A, depth, or
+ stencil index values to obtain a texture with the base internal format
+ specified by <internalformat>. Table 3.8 summarizes the mapping of R, G,
+ B, A, depth, or stencil values to texture components, as a function of the
+ base internal format of the texture image. <internalformat> may be
+ specified as one of the internal format symbolic constants listed in
+ table 3.8. Specifying a value for <internalformat> that is not one of the
+ above values generates the error INVALID_VALUE. If <internalformat> does
+ not match <format>, the error INVALID_OPERATION is generated.
+
+ Textures with a base internal format of DEPTH_COMPONENT or
+ DEPTH_STENCIL_OES are supported by texture image specification commands
+ only if <target> is TEXTURE_2D. Using these formats in conjunction with
+ any other <target> will result in an INVALID_OPERATION error.
+
+ Textures with a base internal format of DEPTH_COMPONENT or
+ DEPTH_STENCIL_OES only support one level of image data. Specifying a
+ non-zero value for <level> will result in an INVALID_OPERATION error.
+
+ Textures with a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL_OES
+ require either depth component data or depth/stencil component data.
+ Textures with other base internal formats require RGBA component data. The
+ error INVALID_OPERATION is generated if the base internal format is
+ DEPTH_COMPONENT or DEPTH_STENCIL_OES and <format> is not DEPTH_COMPONENT or
+ DEPTH_STENCIL_OES, or if the base internal format is not DEPTH_COMPONENT or
+ DEPTH_STENCIL_OES and <format> is DEPTH_COMPONENT or DEPTH_STENCIL_OES.
+
+ Textures with a base internal format of DEPTH_COMPONENT or
+ DEPTH_STENCIL_OES do not support loading image data via the TexImage
+ commands. They can only have their contents specified by rendering
+ to them. The INVALID_OPERATION error is generated by the TexImage2D
+ command if <data> is not NULL for such textures."
+
+ Add a row to table 3.8 (page 68), and update the title of the
+ second column:
+
+ Base Internal Format RGBA, Depth and Stencil Values Internal Components
+ -------------------------------------------------------------------------
+ ... ... ...
+ DEPTH_COMPONENT Depth D
+ DEPTH_STENCIL_OES Depth,Stencil D,S
+ ... ... ...
+
+ Update the caption for table 3.8 (page 68)
+
+ "Table 3.8: Conversion from RGBA, depth, and stencil pixel components to
+ internal texture components. Texture components R, G, B, A, and L are
+ converted back to RGBA colors during filtering as shown in table 3.12.
+ Texture components D are converted to RGBA colors as described in
+ section 3.7.8-1/2."
+
+ Add the following to section 3.7.2 "Alternate Texture Image Specification
+ Commands":
+
+ "CopyTexImage2D and CopyTexSubImage2D generate the INVALID_OPERATION
+ error if the base internal format of the destination texture is
+ DEPTH_COMPONENT or DEPTH_STENCIL_OES.
+
+ TexSubImage2D generates the INVALID_OPERATION error if the base internal
+ format of the texture is DEPTH_COMPONENT or DEPTH_STENCIL_OES."
+
+ Add a new section between sections 3.7.8 and 3.7.9:
+
+ "3.7.8-1/2 Depth/Stencil Textures
+
+ If the currently bound texture's base internal format is DEPTH_COMPONENT or
+ DEPTH_STENCIL_OES, then the output of the texture unit is as described
+ below. Otherwise, the texture unit operates in the normal manner.
+
+ Let <D_t> be the depth texture value, provided by the shader's texture lookup
+ function. Then the effective texture value is computed as follows:
+ <Tau> = <D_t>
+
+ If the texture image has a base internal format of DEPTH_STENCIL_OES, then
+ the stencil index texture component is ignored. The texture value <Tau> does
+ not include a stencil index component, but includes only the depth
+ component.
+
+ The resulting <Tau> is assigned to <R_t>. In some implementations, <Tau> is
+ also assigned to <G_t>, <B_t>, or <A_t>. Thus in table 3.12, textures with
+ depth component data behave as if their base internal format is RGBA, with
+ values in <G_t>, <B_t>, and <A_t> being implementation dependent."
+
+ Add the following to section 3.7.11 "Mipmap Generation":
+
+ "If the level zero array contains depth or depth-stencil data, the
+ error INVALID_OPERATION is generated."
+
+ Insert a new paragraph after the first paragraph of the "Texture Access"
+ subsection of section 3.8.2 on page 87, which says:
+
+ "Texture lookups involving textures with depth component data generate
+ a texture source color by using depth data directly, as described in
+ section 3.7.8-1/2. The stencil texture internal component is ignored
+ if the base internal format is DEPTH_STENCIL_OES."
+
+Additions to Chapter 4 of the OpenGL ES 2.0 specification (Per-Fragment
+Operations and the Framebuffer)
+
+ In section 4.4.5 "Framebuffer Completeness", replace the the 3rd
+ paragraph with the following text:
+
+ "* An internal format is color-renderable if it is one of the formats
+ from table 4.5 noted as color-renderable or if it is unsized format
+ RGBA or RGB. No other formats, including compressed internal formats,
+ are color-renderable.
+
+ * An internal format is depth-renderable if it is one of the sized
+ internal formats from table 4.5 noted as depth-renderable, if it
+ is the unsized format DEPTH_COMPONENT or if it is the internal
+ format value of DEPTH24_STENCIL8_OES. No other formats are
+ depth-renderable.
+
+ * An internal format is stencil-renderable if it is one of the sized
+ internal formats from table 4.5 noted as stencil-renderable or if it
+ is DEPTH24_STENCIL8_OES. No other formats are stencil-renderable."
+
+Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special
+Functions)
+
+ None.
+
+Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State
+Requests)
+
+ None.
+
+Interactions with OES_packed_depth_stencil
+
+ If OES_packed_depth_stencil is not supported, mentions of
+ DEPTH_STENCIL_OES and UNSIGNED_INT_24_8_OES as a format/type combinations
+ for TexImage2D and TexSubImage2D are omitted. Mentions of
+ the internal format DEPTH24_STENCIL8_OES are also omitted.
+
+Interactions with EXT_texture_storage
+
+ If EXT_texture_storage is supported the following internalformat
+ to format/type mappings are used:
+
+ <internalformat> <format> <type>
+ ---------------- -------- ------
+ DEPTH_COMPONENT16 DEPTH_COMPONENT UNSIGNED_SHORT
+ DEPTH_COMPONENT32_OES DEPTH_COMPONENT UNSIGNED_INT
+ DEPTH24_STENCIL8_OES DEPTH_STENCIL_OES UNSIGNED_INT
+
+ Textures with the above <internalformats> only support one level of
+ image data. Specifying a value other than one for the <levels> parameter
+ to TexStorage2DEXT will result in an INVALID_OPERATION error.
+
+ If EXT_texture_storage is not supported, ignore any references
+ to TexStorage2DEXT.
+
+Errors
+
+ The error INVALID_OPERATION is generated by TexImage2D if <format> and
+ <internalformat> are DEPTH_COMPONENT and <type> is not UNSIGNED_SHORT,
+ or UNSIGNED_INT.
+
+ The error INVALID_OPERATION is generated by TexSubImage2D if <format> is
+ DEPTH_COMPONENT and <type> is not UNSIGNED_SHORT, or UNSIGNED_INT.
+
+ The error INVALID_OPERATION is generated by TexImage2D if <format> and
+ <internalformat> are not DEPTH_COMPONENT and <type> is UNSIGNED_SHORT,
+ or UNSIGNED_INT.
+
+ The error INVALID_OPERATION is generated by TexSubImage2D if <format> is
+ not DEPTH_COMPONENT and <type> is UNSIGNED_SHORT, or UNSIGNED_INT.
+
+ The error INVALID_OPERATION is generated by TexImage2D if <format> and
+ <internalformat> are DEPTH_STENCIL_OES and <type> is not
+ UNSIGNED_INT_24_8_OES.
+
+ The error INVALID_OPERATION is generated by TexSubImage2D if <format>
+ is DEPTH_STENCIL_OES and <type> is not UNSIGNED_INT_24_8_OES.
+
+ The error INVALID_OPERATION is generated by TexImage2D if <format> and
+ <internalformat> is not DEPTH_STENCIL_OES and <type> is
+ UNSIGNED_INT_24_8_OES.
+
+ The error INVALID_OPERATION is generated by TexSubImage2D if <format>
+ is not DEPTH_STENCIL_OES and <type> is UNSIGNED_INT_24_8_OES.
+
+ The error INVALID_OPERATION is generated in the following situations:
+ - TexImage2D is called with <format> and <internalformat> of
+ DEPTH_COMPONENT or DEPTH_STENCIL_OES and
+ - <target> is not TEXTURE_2D,
+ - <data> is not NULL, or
+ - <level> is not zero.
+ - TexSubImage2D is called with <format> of DEPTH_COMPONENT or
+ DEPTH_STENCIL_OES.
+ - TexStorage2DEXT is called with <internalformat> of DEPTH_COMPONENT16,
+ DEPTH_COMPONENT32_OES, or DEPTH24_STENCIL8_OES, and
+ - <target> is not TEXTURE_2D, or
+ - <levels> is not one.
+ - CopyTexImage2D is called with an <internalformat> that has a base
+ internal format of DEPTH_COMPONENT or DEPTH_STENCIL_OES.
+ - CopyTexSubImage2D is called with a target texture that has a base
+ internal format of DEPTH_COMPONENT or DEPTH_STENCIL_OES.
+ - GenerateMipmap is called on a texture that has a base internal format
+ of DEPTH_COMPONENT or DEPTH_STENCIL_OES.
+
+New State
+
+ None.
+
+Issues
+
+ 1) What are the differences between this extension and OES_depth_texture
+ and OES_packed_depth_stencil?
+
+ RESOLVED: This extension:
+ - does not support loading pre-baked depth stencil data via
+ TexImage2D or TexSubImage2D.
+ - allows variability in the y-, z-, and w-components of the sample
+ results from depth textures.
+ - only supports one level textures.
+ - explicitly lists the errors for unsupported functionality.
+ Since these were not clearly specified in the OES_depth_texture
+ extension there may be differences in error values between
+ implementations of OES_depth_texture and ANGLE_depth_texture.
+ This specification was also rebased to apply against the OpenGL ES 2.0
+ specification instead of the OpenGL specification, making it more
+ obvious what all the functionality changes are.
+
+ 2) Why does TexSubImage2D accept the new format/type combinations even
+ though it does not actually support loading data?
+
+ RESOLVED: This was done to be more consistent with the OES_depth_texture
+ extension and to make it easier to add support for loading texture
+ data if it is possible to support in the future.
+
+ 3) Why are only 1-level depth textures supported?
+
+ RESOLVED: The only use for multiple levels of depth textures would
+ be for fitlered texturing. However since it is not possible to
+ render to non-zero-level texture levels in OpenGL ES 2.0, and since
+ this extension forbids loading existing data and GenerateMipmap on
+ depth textures, it is impossible to initialize or specify contents
+ for non-zero levels of depth textures.
+
+Revision History
+
+ 02/25/2013 swoods revise to allow texture lookup to guarantee depth values
+ only in red channel of sample result.
+ 06/04/2012 dgkoch fix errors, disallow multi-level depth textures.
+ 05/30/2012 dgkoch minor updates and add issues.
+ 05/23/2012 dgkoch intial revision based on OES_depth_texture and
+ OES_packed_depth_stencil and rebased against the ES 2.0 spec
+
diff --git a/extensions/ANGLE_framebuffer_blit.txt b/extensions/ANGLE_framebuffer_blit.txt
new file mode 100644
index 00000000..53056c44
--- /dev/null
+++ b/extensions/ANGLE_framebuffer_blit.txt
@@ -0,0 +1,437 @@
+Name
+
+ ANGLE_framebuffer_blit
+
+Name Strings
+
+ GL_ANGLE_framebuffer_blit
+
+Contributors
+
+ Contributors to EXT_framebuffer_blit
+ Daniel Koch, TransGaming Inc.
+ Shannon Woods, TransGaming Inc.
+ Kenneth Russell, Google Inc.
+ Vangelis Kokkevis, Google Inc.
+
+Contact
+
+ Daniel Koch, TransGaming Inc. (daniel 'at' transgaming 'dot' com)
+
+Status
+
+ Implemented in ANGLE ES2
+
+Version
+
+ Last Modified Date: Sept 22, 2012
+ Author Revision: 4
+
+Number
+
+ OpenGL ES Extension #83
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+ The extension is written against the OpenGL ES 2.0 specification.
+
+ OES_texture_3D affects the definition of this extension.
+
+Overview
+
+ This extension modifies framebuffer objects by splitting the
+ framebuffer object binding point into separate DRAW and READ
+ bindings. This allows copying directly from one framebuffer to
+ another. In addition, a new high performance blit function is
+ added to facilitate these blits and perform some data conversion
+ where allowed.
+
+IP Status
+
+ No known IP claims.
+
+New Procedures and Functions
+
+ void BlitFramebufferANGLE(int srcX0, int srcY0, int srcX1, int srcY1,
+ int dstX0, int dstY0, int dstX1, int dstY1,
+ bitfield mask, enum filter);
+
+New Tokens
+
+ Accepted by the <target> parameter of BindFramebuffer,
+ CheckFramebufferStatus, FramebufferTexture2D, FramebufferTexture3DOES,
+ FramebufferRenderbuffer, and
+ GetFramebufferAttachmentParameteriv:
+
+ // (reusing the tokens from EXT_framebuffer_blit)
+ READ_FRAMEBUFFER_ANGLE 0x8CA8
+ DRAW_FRAMEBUFFER_ANGLE 0x8CA9
+
+ Accepted by the <pname> parameters of GetIntegerv and GetFloatv:
+
+ // (reusing the tokens from EXT_framebuffer_blit)
+ DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6 // alias FRAMEBUFFER_BINDING
+ READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA
+
+
+Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)
+
+ Change the last paragraph of section 3.7.2 (Alternate Texture Image
+ Specification Commands) to:
+
+ "Calling CopyTexSubImage3DOES, CopyTexImage2D or CopyTexSubImage2D will
+ result in an INVALID_FRAMEBUFFER_OPERATION error if the object bound
+ to READ_FRAMEBUFFER_BINDING_ANGLE is not "framebuffer complete"
+ (section 4.4.4.2)."
+
+Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment
+Operations and the Framebuffer)
+
+ Change the first word of Chapter 4 from "The" to "A".
+
+ Append to the introduction of Chapter 4:
+
+ "Conceptually, the GL has two active framebuffers; the draw
+ framebuffer is the destination for rendering operations, and the
+ read framebuffer is the source for readback operations. The same
+ framebuffer may be used for both drawing and reading. Section
+ 4.4.1 describes the mechanism for controlling framebuffer usage."
+
+ Modify the first sentence of the last paragraph of section 4.1.1 as follows:
+
+ "While an application-created framebuffer object is bound to
+ DRAW_FRAMEBUFFER_ANGLE, the pixel ownership test always passes."
+
+ Add to 4.3.1 (Reading Pixels), right before the subsection titled
+ "Obtaining Pixels from the Framebuffer":
+
+ "Calling ReadPixels generates INVALID_FRAMEBUFFER_OPERATION if
+ the object bound to READ_FRAMEBUFFER_BINDING_ANGLE is not "framebuffer
+ complete" (section 4.4.4.2). GetIntegerv generates an INVALID_OPERATION
+ error if the object bound to READ_FRAMEBUFFER_BINDING_ANGLE is not
+ framebuffer complete, or if the GL is using a framebuffer object
+ (i.e. READ_FRAMEBUFFER_BINDING_ANGLE is non-zero) and there is no color
+ attachment."
+
+ Insert a new section 4.3.2 titled "Copying Pixels" and renumber the
+ subsequent sections. Add the following text:
+
+ "BlitFramebufferANGLE transfers a rectangle of pixel values from one
+ region of the read framebuffer to another in the draw framebuffer.
+
+ BlitFramebufferANGLE(int srcX0, int srcY0, int srcX1, int srcY1,
+ int dstX0, int dstY0, int dstX1, int dstY1,
+ bitfield mask, enum filter);
+
+ <mask> is the bitwise OR of a number of values indicating which
+ buffers are to be copied. The values are COLOR_BUFFER_BIT,
+ DEPTH_BUFFER_BIT, and STENCIL_BUFFER_BIT, which are described in
+ section 4.2.3. The pixels corresponding to these buffers are
+ copied from the source rectangle, bound by the locations (srcX0,
+ srcY0) and (srcX1, srcY1), to the destination rectangle, bound by
+ the locations (dstX0, dstY0) and (dstX1, dstY1). The lower bounds
+ of the rectangle are inclusive, while the upper bounds are
+ exclusive.
+
+ The actual region taken from the read framebuffer is limited to the
+ intersection of the source buffers being transferred, which may include
+ the color buffer, the depth buffer, and/or the stencil buffer depending on
+ <mask>. The actual region written to the draw framebuffer is limited to the
+ intersection of the destination buffers being written, which may include
+ the color buffer, the depth buffer, and/or the stencil buffer
+ depending on <mask>. Whether or not the source or destination regions are
+ altered due to these limits, the offset applied to pixels being transferred
+ is performed as though no such limits were present.
+
+ Stretching and scaling during a copy are not supported. If the source
+ and destination rectangle dimensions do not match, no copy is
+ performed and an INVALID_OPERATION error is generated.
+ Because stretching is not supported, <filter> must be NEAREST and
+ no filtering is applied.
+
+ Flipping during a copy is not supported. If either the source or
+ destination rectangle specifies a negative dimension, the error
+ INVALID_OPERATION is generated. If both the source and
+ destination rectangles specify a negative dimension for the same
+ direction, no reversal is required and the operation is supported.
+
+ If the source and destination buffers are identical, and the
+ source and destination rectangles overlap, the result of the blit
+ operation is undefined.
+
+ The pixel copy bypasses the fragment pipeline. The only fragment
+ operations which affect the blit are the pixel ownership test and
+ the scissor test.
+
+ If a buffer is specified in <mask> and does not exist in both the
+ read and draw framebuffers, the corresponding bit is silently
+ ignored.
+
+ Calling BlitFramebufferANGLE will result in an
+ INVALID_FRAMEBUFFER_OPERATION error if the objects bound to
+ DRAW_FRAMEBUFFER_BINDING_ANGLE and READ_FRAMEBUFFER_BINDING_ANGLE are
+ not "framebuffer complete" (section 4.4.4.2)."
+
+ Calling BlitFramebufferANGLE will result in an INVALID_OPERATION
+ error if <mask> includes COLOR_BUFFER_BIT and the source and
+ destination color formats to not match.
+
+ Calling BlitFramebufferANGLE will result in an INVALID_OPERATION
+ error if <mask> includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT
+ and the source and destination depth and stencil buffer formats do
+ not match.
+
+ If <mask> includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT, only
+ complete buffers can be copied. If the source rectangle does not
+ specify the complete source buffer or the destination rectangle
+ (after factoring the scissor region, if applicable) does not specify
+ the complete destination buffer, an INVALID_OPERATION
+ error is generated.
+
+ Modify the beginning of section 4.4.1 as follows:
+
+ "The default framebuffer for rendering and readback operations is
+ provided by the windowing system. In addition, named framebuffer
+ objects can be created and operated upon. The namespace for
+ framebuffer objects is the unsigned integers, with zero reserved
+ by the GL for the default framebuffer.
+
+ A framebuffer object is created by binding an unused name to
+ DRAW_FRAMEBUFFER_ANGLE or READ_FRAMEBUFFER_ANGLE. The binding is
+ effected by calling
+
+ void BindFramebuffer(enum target, uint framebuffer);
+
+ with <target> set to the desired framebuffer target and
+ <framebuffer> set to the unused name. The resulting framebuffer
+ object is a new state vector, comprising one set of the state values
+ listed in table 6.23 for each attachment point of the
+ framebuffer, set to the same initial values. There is one
+ color attachment point, plus one each
+ for the depth and stencil attachment points.
+
+ BindFramebuffer may also be used to bind an existing
+ framebuffer object to DRAW_FRAMEBUFFER_ANGLE or
+ READ_FRAMEBUFFER_ANGLE. If the bind is successful no change is made
+ to the state of the bound framebuffer object, and any previous
+ binding to <target> is broken.
+
+ If a framebuffer object is bound to DRAW_FRAMEBUFFER_ANGLE or
+ READ_FRAMEBUFFER_ANGLE, it becomes the target for rendering or
+ readback operations, respectively, until it is deleted or another
+ framebuffer is bound to the corresponding bind point. Calling
+ BindFramebuffer with <target> set to FRAMEBUFFER binds the
+ framebuffer to both DRAW_FRAMEBUFFER_ANGLE and READ_FRAMEBUFFER_ANGLE.
+
+ While a framebuffer object is bound, GL operations on the target
+ to which it is bound affect the images attached to the bound
+ framebuffer object, and queries of the target to which it is bound
+ return state from the bound object. Queries of the values
+ specified in table 6.20 (Implementation Dependent Pixel Depths)
+ and table 6.yy (Framebuffer Dependent Values) are
+ derived from the framebuffer object bound to DRAW_FRAMEBUFFER_ANGLE.
+
+ The initial state of DRAW_FRAMEBUFFER_ANGLE and READ_FRAMEBUFFER_ANGLE
+ refers to the default framebuffer provided by the windowing
+ system. In order that access to the default framebuffer is not
+ lost, it is treated as a framebuffer object with the name of 0.
+ The default framebuffer is therefore rendered to and read from
+ while 0 is bound to the corresponding targets. On some
+ implementations, the properties of the default framebuffer can
+ change over time (e.g., in response to windowing system events
+ such as attaching the context to a new windowing system drawable.)"
+
+ Change the description of DeleteFramebuffers as follows:
+
+ "<framebuffers> contains <n> names of framebuffer objects to be
+ deleted. After a framebuffer object is deleted, it has no
+ attachments, and its name is again unused. If a framebuffer that
+ is currently bound to one or more of the targets
+ DRAW_FRAMEBUFFER_ANGLE or READ_FRAMEBUFFER_ANGLE is deleted, it is as
+ though BindFramebuffer had been executed with the corresponding
+ <target> and <framebuffer> zero. Unused names in <framebuffers>
+ are silently ignored, as is the value zero."
+
+
+ In section 4.4.3 (Renderbuffer Objects), modify the first two sentences
+ of the description of FramebufferRenderbuffer as follows:
+
+ "<target> must be DRAW_FRAMEBUFFER_ANGLE, READ_FRAMEBUFFER_ANGLE, or
+ FRAMEBUFFER. If <target> is FRAMEBUFFER, it behaves as
+ though DRAW_FRAMEBUFFER_ANGLE was specified. The INVALID_OPERATION
+ error is generated if the value of the corresponding binding is zero."
+
+ In section 4.4.3 (Renderbuffer Objects), modify the first two sentences
+ of the description of FramebufferTexture2D as follows:
+
+ "<target> must be DRAW_FRAMEBUFFER_ANGLE,
+ READ_FRAMEBUFFER_ANGLE, or FRAMEBUFFER. If <target> is
+ FRAMEBUFFER, it behaves as though DRAW_FRAMEBUFFER_ANGLE was
+ specified. The INVALID_OPERATION error is generated if the value of the
+ corresponding binding is zero."
+
+ In section 4.4.5 (Framebuffer Completeness), modify the first sentence
+ of the description of CheckFramebufferStatus as follows:
+
+ "If <target> is not DRAW_FRAMEBUFFER_ANGLE, READ_FRAMEBUFFER_ANGLE or
+ FRAMEBUFFER, the error INVALID_ENUM is generated. If <target> is
+ FRAMEBUFFER, it behaves as though DRAW_FRAMEBUFFER_ANGLE was
+ specified."
+
+ Modify the first sentence of the subsection titled "Effects of Framebuffer
+ Completeness on Framebuffer Operations" to be:
+
+ "Attempting to render to or read from a framebuffer which is not
+ framebuffer complete will generate an
+ INVALID_FRAMEBUFFER_OPERATION error."
+
+
+
+Additions to Chapter 6 of the OpenGL 1.5 Specification (State and State
+Requests)
+
+ In section 6.1.3, modify the first sentence of the description of
+ GetFramebufferAttachmentParameteriv as follows:
+
+ "<target> must be DRAW_FRAMEBUFFER_ANGLE, READ_FRAMEBUFFER_ANGLE or
+ FRAMEBUFFER. If <target> is FRAMEBUFFER, it behaves as
+ though DRAW_FRAMEBUFFER_ANGLE was specified."
+
+ Modify the title of Table 6.23 (Framebuffer State) to be "Framebuffer
+ (state per attachment point)".
+
+
+Dependencies on OES_texture_3D
+
+ On an OpenGL ES implementation, in the absense of OES_texture_3D,
+ omit references to FramebufferTexture3DOES and CopyTexSubImage3DOES.
+
+Errors
+
+ The error INVALID_FRAMEBUFFER_OPERATION is generated if
+ BlitFramebufferANGLE is called while the
+ draw framebuffer is not framebuffer complete.
+
+ The error INVALID_FRAMEBUFFER_OPERATION is generated if
+ BlitFramebufferANGLE, ReadPixels, CopyTex{Sub}Image*, is called while the
+ read framebuffer is not framebuffer complete.
+
+ The error INVALID_OPERATION is generated if GetIntegerv is called
+ while the read framebuffer is not framebuffer complete, or if there
+ is no color attachment present on the read framebuffer object.
+
+ The error INVALID_VALUE is generated by BlitFramebufferANGLE if
+ <mask> has any bits set other than those named by
+ COLOR_BUFFER_BIT, DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT.
+
+ The error INVALID_OPERATION is generated if BlitFramebufferANGLE is
+ called and <mask> includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT
+ and the source and destination depth or stencil buffer formats do
+ not match.
+
+ The error INVALID_OPERATION is generated if BlitFramebufferANGLE is
+ called and any of the following conditions are true:
+ - the source and destination rectangle dimensions do not match
+ (ie scaling or flipping is required).
+ - <mask> includes COLOR_BUFFER_BIT and the source and destination
+ buffer formats do not match.
+ - <mask> includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT and the
+ source or destination rectangles do not specify the entire source
+ or destination buffer (after applying any scissor region).
+
+ The error INVALID_ENUM is generated by BlitFramebufferANGLE if
+ <filter> is not NEAREST.
+
+ The error INVALID_ENUM is generated if BindFramebuffer,
+ CheckFramebufferStatus, FramebufferTexture{2D|3DOES},
+ FramebufferRenderbuffer, or
+ GetFramebufferAttachmentParameteriv is called and <target> is
+ not DRAW_FRAMEBUFFER_ANGLE, READ_FRAMEBUFFER_ANGLE or FRAMEBUFFER.
+
+New State
+
+ (Add a new table 6.xx, "Framebuffer (state per framebuffer target binding point)")
+
+ Get Value Type Get Command Initial Value Description Section
+ ------------------------------ ---- ----------- -------------- ------------------- ------------
+ DRAW_FRAMEBUFFER_BINDING_ANGLE Z+ GetIntegerv 0 framebuffer object bound 4.4.1
+ to DRAW_FRAMEBUFFER_ANGLE
+ READ_FRAMEBUFFER_BINDING_ANGLE Z+ GetIntegerv 0 framebuffer object 4.4.1
+ to READ_FRAMEBUFFER_ANGLE
+
+ Remove reference to FRAMEBUFFER_BINDING from Table 6.23.
+
+ (Add a new table 6.yy, "Framebuffer Dependent Values")
+
+ Get Value Type Get Command Initial Value Description Section
+ ---------------------------- ---- ----------- -------------- ------------------- ------------
+ SAMPLE_BUFFERS Z+ GetIntegerv 0 Number of multisample 3.2
+ buffers
+ SAMPLES Z+ GetIntegerv 0 Coverage mask size 3.2
+
+ Remove the references to SAMPLE_BUFFERS and SAMPLES from Table 6.17.
+
+
+Issues
+
+ 1) What should we call this extension?
+
+ Resolved: ANGLE_framebuffer_blit.
+
+ This extension is a result of a collaboration between Google and
+ TransGaming for the open-source ANGLE project. Typically one would
+ label a multi-vendor extension as EXT, but EXT_framebuffer_blit
+ is already the name for this on Desktop GL. Additionally this
+ isn't truely a multi-vendor extension because there is only one
+ implementation of this. We'll follow the example of the open-source
+ MESA project which uses the project name for the vendor suffix.
+
+ 2) Why is this done as a separate extension instead of just supporting
+ EXT_framebuffer_blit?
+
+ To date, EXT_framebuffer_blit has not had interactions with OpenGL ES
+ specified and, as far as we know, it has not previously been exposed on
+ an ES 1.1 or ES 2.0 implementation. Because there are enough
+ differences between Desktop GL and OpenGL ES, and since OpenGL ES 2.0
+ has already subsumed the EXT_framebuffer_object functionality (with
+ some changes) it was deemed a worthwhile exercise to fully specify the
+ interactions. Additionally, some of the choices in exactly which
+ functionality is supported by BlitFramebufferANGLE is dictated by
+ what is reasonable to support on a implementation which is
+ layered on Direct3D9. It is not expected that other implementations
+ will necessary have the same set of restrictions or requirements.
+
+ 3) How does this extension differ from EXT_framebuffer_blit?
+
+ This extension is designed to be a pure subset of the
+ EXT_framebuffer_blit functionality as applicable to OpenGL ES 2.0.
+
+ Functionality that is unchanged:
+ - the split DRAW and READ framebuffer attachment points and related sematics.
+ - the token values for the DRAW/READ_FRAMEBUFFER and DRAW/READ_FRAMBUFFER_BINDING
+ - the signature of the BlitFramebuffer entry-point.
+
+ Additional restrictions imposed by BlitFramebufferANGLE:
+ - no color conversions are supported
+ - no scaling, stretching or flipping are supported
+ - no filtering is supported (a consequence of no stretching)
+ - only whole depth and/or stencil buffers can be copied
+
+Revision History
+
+ Revision 1, 2010/07/06
+ - copied from revision 15 of EXT_framebuffer_object
+ - removed language that was clearly not relevant to ES2
+ - rebased changes against the OpenGL ES 2.0 specification
+ - added ANGLE-specific restrictions
+ Revision 2, 2010/07/15
+ - clarifications of implicit clamping to buffer sizes (from ARB_fbo)
+ - clarify that D/S restricts apply after the scissor is applied
+ - improve some error language
+ Revision 3, 2010/08/06
+ - add additional contributors, update implementation status
+ Revision 4, 2012/09/22
+ - document errors for GetIntegerv.
+
diff --git a/extensions/ANGLE_framebuffer_multisample.txt b/extensions/ANGLE_framebuffer_multisample.txt
new file mode 100644
index 00000000..cf5e4583
--- /dev/null
+++ b/extensions/ANGLE_framebuffer_multisample.txt
@@ -0,0 +1,363 @@
+Name
+
+ ANGLE_framebuffer_multisample
+
+Name Strings
+
+ GL_ANGLE_framebuffer_multisample
+
+Contributors
+
+ Contributors to EXT_framebuffer_multisample
+ Daniel Koch, TransGaming Inc.
+ Shannon Woods, TransGaming Inc.
+ Kenneth Russell, Google Inc.
+ Vangelis Kokkevis, Google Inc.
+
+Contacts
+
+ Daniel Koch, TransGaming Inc. (daniel 'at' transgaming 'dot' com)
+
+Status
+
+ Implemented in ANGLE ES2
+
+Version
+
+ Last Modified Date: Aug 6, 2010
+ Author Revision: #3
+
+Number
+
+ OpenGL ES Extension #84
+
+Dependencies
+
+ Requires OpenGL ES 2.0.
+
+ Requires GL_ANGLE_framebuffer_blit (or equivalent functionality).
+
+ The extension is written against the OpenGL ES 2.0 specification.
+
+ OES_texture_3D affects the definition of this extension.
+
+Overview
+
+ This extension extends the framebuffer object framework to
+ enable multisample rendering.
+
+ The new operation RenderbufferStorageMultisampleANGLE() allocates
+ storage for a renderbuffer object that can be used as a multisample
+ buffer. A multisample render buffer image differs from a
+ single-sample render buffer image in that a multisample image has a
+ number of SAMPLES that is greater than zero. No method is provided
+ for creating multisample texture images.
+
+ All of the framebuffer-attachable images attached to a framebuffer
+ object must have the same number of SAMPLES or else the framebuffer
+ object is not "framebuffer complete". If a framebuffer object with
+ multisample attachments is "framebuffer complete", then the
+ framebuffer object behaves as if SAMPLE_BUFFERS is one.
+
+ The resolve operation is affected by calling
+ BlitFramebufferANGLE (provided by the ANGLE_framebuffer_blit
+ extension) where the source is a multisample application-created
+ framebuffer object and the destination is a single-sample
+ framebuffer object (either application-created or window-system
+ provided).
+
+New Procedures and Functions
+
+ void RenderbufferStorageMultisampleANGLE(
+ enum target, sizei samples,
+ enum internalformat,
+ sizei width, sizei height);
+
+New Types
+
+ None.
+
+New Tokens
+
+ Accepted by the <pname> parameter of GetRenderbufferParameteriv:
+
+ RENDERBUFFER_SAMPLES_ANGLE 0x8CAB
+
+ Returned by CheckFramebufferStatus:
+
+ FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56
+
+ Accepted by the <pname> parameter of GetBooleanv, GetIntegerv,
+ and GetFloatv:
+
+ MAX_SAMPLES_ANGLE 0x8D57
+
+Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL Operation)
+
+Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)
+
+ Add to the last paragraph of 3.7.2 (Alternate Texture Image Specification)
+ (as modified by ANGLE_framebuffer_blit) the following:
+
+ "Calling CopyTexSubImage3DOES, CopyTexImage2D or CopyTexSubImage2D will
+ result in INVALID_OPERATION being generated if the object bound to
+ READ_FRAMEBUFFER_BINDING_ANGLE is "framebuffer complete" and the value
+ of SAMPLE_BUFFERS is greater than zero."
+
+Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment
+Operations and the Framebuffer)
+
+ Add to 4.3.1 (Reading Pixels), right before the subsection titled
+ "Obtaining Pixels from the Framebuffer":
+
+ "ReadPixels generates INVALID_OPERATION if READ_FRAMEBUFFER_BINDING_ANGLE
+ (section 4.4) is non-zero, the read framebuffer is framebuffer
+ complete, and the value of SAMPLE_BUFFERS for the read framebuffer
+ is greater than zero."
+
+ In 4.3.2 (Copying Pixels), add to the section describing BlitFramebuffer
+ that was added by ANGLE_framebuffer_blit.
+
+ "If SAMPLE_BUFFERS for the read framebuffer is greater than zero and
+ SAMPLE_BUFFERS for the draw framebuffer is zero, the samples
+ corresponding to each pixel location in the source are converted to
+ a single sample before being written to the destination.
+
+ If SAMPLE_BUFFERS for the draw framebuffer is greater than zero,
+ no copy is performed and an INVALID_OPERATION error is generated.
+
+ If SAMPLE_BUFFERS for the read framebuffer is greater than zero and
+ <mask> includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT, no copy is
+ performed and an INVALID_OPERATION error is generated.
+
+ If SAMPLE_BUFFERS for the read framebuffer is greater than zero and
+ the format of the read and draw framebuffers are not identical, no
+ copy is performed and an INVALID_OPERATION error is generated.
+
+ If SAMPLE_BUFFERS for the read framebuffer is greater than zero, the
+ dimensions of the source and destination rectangles provided to
+ BlitFramebufferANGLE must be identical and must specify the complete
+ source and destination buffers, otherwise no copy is performed and
+ an INVALID_OPERATION error is generated."
+
+ Modification to 4.4.3 (Renderbuffer Objects)
+
+ Add, just above the definition of RenderbufferStorage:
+
+ "The command
+
+ void RenderbufferStorageMultisampleANGLE(
+ enum target, sizei samples,
+ enum internalformat,
+ sizei width, sizei height);
+
+ establishes the data storage, format, dimensions, and number of
+ samples of a renderbuffer object's image. <target> must be
+ RENDERBUFFER. <internalformat> must be one of the color-renderable,
+ depth-renderable, or stencil-renderable formats described in table 4.5.
+ <width> and <height> are the dimensions in pixels of the renderbuffer. If
+ either <width> or <height> is greater than the value of
+ MAX_RENDERBUFFER_SIZE, or if <samples> is greater than MAX_SAMPLES_ANGLE,
+ then the error INVALID_VALUE is generated. If OpenGL ES is unable to
+ create a data store of the requested size, the error OUT_OF_MEMORY
+ is generated.
+
+ Upon success, RenderbufferStorageMultisampleANGLE deletes any existing
+ data store for the renderbuffer image and the contents of the data
+ store after calling RenderbufferStorageMultisampleANGLE are undefined.
+ RENDERBUFFER_WIDTH is set to <width>, RENDERBUFFER_HEIGHT is
+ set to <height>, and RENDERBUFFER_INTERNAL_FORMAT is set to
+ <internalformat>.
+
+ If <samples> is zero, then RENDERBUFFER_SAMPLES_ANGLE is set to zero.
+ Otherwise <samples> represents a request for a desired minimum
+ number of samples. Since different implementations may support
+ different sample counts for multisampled rendering, the actual
+ number of samples allocated for the renderbuffer image is
+ implementation dependent. However, the resulting value for
+ RENDERBUFFER_SAMPLES_ANGLE is guaranteed to be greater than or equal
+ to <samples> and no more than the next larger sample count supported
+ by the implementation.
+
+ An OpenGL ES implementation may vary its allocation of internal component
+ resolution based on any RenderbufferStorageMultisampleANGLE parameter (except
+ target), but the allocation and chosen internal format must not be a
+ function of any other state and cannot be changed once they are
+ established. The actual resolution in bits of each component of the
+ allocated image can be queried with GetRenderbufferParameteriv."
+
+ Modify the definiton of RenderbufferStorage as follows:
+
+ "The command
+
+ void RenderbufferStorage(enum target, enum internalformat,
+ sizei width, sizei height);
+
+ is equivalent to calling RenderbufferStorageMultisampleANGLE with
+ <samples> equal to zero."
+
+ In section 4.4.5 (Framebuffer Completeness) in the subsection
+ titled "Framebuffer Completeness" add an entry to the bullet list:
+
+ * The value of RENDERBUFFER_SAMPLES_ANGLE is the same for all attached
+ images.
+ { FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE }
+
+ Also add a paragraph to the end of the section after the definition
+ of CheckFramebufferStatus:
+
+ "The values of SAMPLE_BUFFERS and SAMPLES are derived from the
+ attachments of the currently bound framebuffer object. If the
+ current DRAW_FRAMEBUFFER_BINDING_ANGLE is not "framebuffer complete",
+ then both SAMPLE_BUFFERS and SAMPLES are undefined. Otherwise,
+ SAMPLES is equal to the value of RENDERBUFFER_SAMPLES_ANGLE for the
+ attached images (which all must have the same value for
+ RENDERBUFFER_SAMPLES_ANGLE). Further, SAMPLE_BUFFERS is one if
+ SAMPLES is non-zero. Otherwise, SAMPLE_BUFFERS is zero.
+
+Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions)
+
+
+Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State
+Requests)
+
+ In section 6.1.3 (Enumeraged Queries), modify the third paragraph
+ of the description of GetRenderbufferParameteriv as follows:
+
+ "Upon successful return from GetRenderbufferParameteriv, if
+ <pname> is RENDERBUFFER_WIDTH, RENDERBUFFER_HEIGHT,
+ RENDERBUFFER_INTERNAL_FORMAT, or RENDERBUFFER_SAMPLES_ANGLE, then <params>
+ will contain the width in pixels, height in pixels, internal format, or
+ number of samples, respectively, of the image of the renderbuffer
+ currently bound to <target>."
+
+
+Dependencies on ANGLE_framebuffer_blit
+
+ ANGLE_framebuffer_blit is required. Technically, ANGLE_framebuffer_blit
+ would not be required to support multisampled rendering, except for
+ the fact that it provides the only method of doing a multisample
+ resovle from a multisample renderbuffer.
+
+Dependencies on OES_texture_3D
+
+ On an OpenGL ES implementation, in the absense of OES_texture_3D,
+ omit references to CopyTexSubImage3DOES.
+
+Errors
+
+ The error INVALID_OPERATION is generated if ReadPixels or
+ CopyTex{Sub}Image* is called while READ_FRAMEBUFFER_BINDING_ANGLE
+ is non-zero, the read framebuffer is framebuffer complete, and the
+ value of SAMPLE_BUFFERS for the read framebuffer is greater than
+ zero.
+
+ If both the draw and read framebuffers are framebuffer complete and
+ the draw framebuffer has a value of SAMPLE_BUFFERS that is greater
+ than zero, then the error INVALID_OPERATION is generated if
+ BlitFramebufferANGLE is called.
+
+ If both the draw and read framebuffers are framebuffer complete and
+ the read framebuffer has a value of SAMPLE_BUFFERS that is greater
+ than zero, the error INVALID_OPERATION is generated if
+ BlitFramebufferANGLE is called and any of the following conditions
+ are true:
+ - <mask> includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT.
+ - the source or destination rectangles do not specify the entire
+ source or destination buffer.
+
+ If both the draw and read framebuffers are framebuffer complete and
+ either has a value of SAMPLE_BUFFERS that is greater than zero, then
+ the error INVALID_OPERATION is generated if BlitFramebufferANGLE is
+ called and the formats of the draw and read framebuffers are not
+ identical.
+
+ If either the draw or read framebuffer is framebuffer complete and
+ has a value of SAMPLE_BUFFERS that is greater than zero, then the
+ error INVALID_OPERATION is generated if BlitFramebufferANGLE is called
+ and the specified source and destination dimensions are not
+ identical.
+
+ If RenderbufferStorageMultisampleANGLE is called with <target> not
+ equal to RENDERBUFFER, the error INVALID_ENUM is generated.
+
+ If RenderbufferStorageMultisampleANGLE is called with an
+ <internalformat> that is not listed as one of the color-, depth-
+ or stencil-renderable formats in Table 4.5, then the error
+ INVALID_ENUM is generated.
+
+ If RenderbufferStorageMultisampleANGLE is called with <width> or
+ <height> greater than MAX_RENDERBUFFER_SIZE, then the error
+ INVALID_VALUE is generated.
+
+ If RenderbufferStorageMultisampleANGLE is called with a value of
+ <samples> that is greater than MAX_SAMPLES_ANGLE or less than zero,
+ then the error INVALID_VALUE is generated.
+
+ The error OUT_OF_MEMORY is generated when
+ RenderbufferStorageMultisampleANGLE cannot create storage of the
+ specified size.
+
+New State
+
+ Add to table 6.22 (Renderbuffer State)
+
+ Get Value Type Get Command Initial Value Description Section
+ ------------------------------- ------ -------------------------- ------------- -------------------- -------
+ RENDERBUFFER_SAMPLES_ANGLE Z+ GetRenderbufferParameteriv 0 number of samples 4.4.3
+
+
+ Add to table 6.yy (Framebuffer Dependent Vaues) (added by
+ ANGLE_framebuffer_blit), the following new framebuffer dependent state.
+
+ Get Value Type Get Command Minimum Value Description Section
+ ----------------- ---- ----------- ------------- ------------------- -------
+ MAX_SAMPLES_ANGLE Z+ GetIntegerv 1 Maximum number of 4.4.3
+ samples supported
+ for multisampling
+
+
+
+Issues
+
+ Issues from EXT_framebuffer_multisample have been removed.
+
+ 1) What should we call this extension?
+
+ Resolved: ANGLE_framebuffer_blit.
+
+ This extension is a result of a collaboration between Google and
+ TransGaming for the open-source ANGLE project. Typically one would
+ label a multi-vendor extension as EXT, but EXT_framebuffer_mulitsample
+ is already the name for this on Desktop GL. Additionally this
+ isn't truely a multi-vendor extension because there is only one
+ implementation of this. We'll follow the example of the open-source
+ MESA project which uses the project name for the vendor suffix.
+
+ 2) How does this extension differ from EXT_framebuffer_multisample?
+
+ This is designed to be a proper subset of EXT_framebuffer_multisample
+ functionality as applicable to OpenGL ES 2.0.
+
+ Functionality that is unchanged:
+ - creation of multisample renderbuffers.
+ - whole buffer multi-sample->single-sample resolve.
+ - no format conversions, stretching or flipping supported on multisample blits.
+
+ Additional restrictions on BlitFramebufferANGLE:
+ - multisample resolve is only supported on color buffers.
+ - no blits to multisample destinations (no single->multi or multi-multi).
+ - only entire buffers can be resolved.
+
+Revision History
+
+ Revision 1, 2010/07/08
+ - copied from revision 7 of EXT_framebuffer_multisample
+ - removed language that was not relevant to ES2
+ - rebase changes against the Open GL ES 2.0 specification
+ - added ANGLE-specific restrictions
+ Revision 2, 2010/07/19
+ - fix missing error code
+ Revision 3, 2010/08/06
+ - add additional contributors, update implementation status
+ - disallow negative samples
diff --git a/extensions/ANGLE_instanced_arrays.txt b/extensions/ANGLE_instanced_arrays.txt
new file mode 100644
index 00000000..69d11504
--- /dev/null
+++ b/extensions/ANGLE_instanced_arrays.txt
@@ -0,0 +1,359 @@
+Name
+
+ ANGLE_instanced_arrays
+
+Name Strings
+
+ GL_ANGLE_instanced_arrays
+
+Contributors
+
+ Contributors to ARB_instanced_arrays
+ Nicolas Capens, TransGaming Inc.
+ James Helferty, TransGaming Inc.
+ Kenneth Russell, Google Inc.
+ Vangelis Kokkevis, Google Inc.
+
+Contact
+
+ Daniel Koch, TransGaming Inc. (daniel 'at' transgaming.com)
+
+Status
+
+ Implemented in ANGLE r976.
+
+Version
+
+ Last Modified Date: February 8, 2012
+ Author Revision: 3
+
+Number
+
+ OpenGL ES Extension #109
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+ This extension is written against the OpenGL ES 2.0 Specification.
+
+Overview
+
+ A common use case in GL for some applications is to be able to
+ draw the same object, or groups of similar objects that share
+ vertex data, primitive count and type, multiple times. This
+ extension provides a means of accelerating such use cases while
+ restricting the number of API calls, and keeping the amount of
+ duplicate data to a minimum.
+
+ This extension introduces an array "divisor" for generic
+ vertex array attributes, which when non-zero specifies that the
+ attribute is "instanced." An instanced attribute does not
+ advance per-vertex as usual, but rather after every <divisor>
+ conceptual draw calls.
+
+ (Attributes which aren't instanced are repeated in their entirety
+ for every conceptual draw call.)
+
+ By specifying transform data in an instanced attribute or series
+ of instanced attributes, vertex shaders can, in concert with the
+ instancing draw calls, draw multiple instances of an object with
+ one draw call.
+
+IP Status
+
+ No known IP claims.
+
+New Tokens
+
+ Accepted by the <pname> parameters of GetVertexAttribfv and
+ GetVertexAttribiv:
+
+ VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE
+
+New Procedures and Functions
+
+ void DrawArraysInstancedANGLE(enum mode, int first, sizei count,
+ sizei primcount);
+
+ void DrawElementsInstancedANGLE(enum mode, sizei count, enum type,
+ const void *indices, sizei primcount);
+
+ void VertexAttribDivisorANGLE(uint index, uint divisor);
+
+Additions to Chapter 2 of the OpenGL ES 2.0 Specification
+(OpenGL ES Operation)
+
+ Modify section 2.8 (Vertex Arrays), p. 21
+
+ After description of EnableVertexAttribArray / DisableVertexAttribArray
+ add the following:
+
+ "The command
+
+ void VertexAttribDivisorANGLE(uint index, uint divisor);
+
+ modifies the rate at which generic vertex attributes advance when
+ rendering multiple instances of primitives in a single draw call
+ (see DrawArraysInstancedANGLE and DrawElementsInstancedANGLE below).
+ If <divisor> is zero, the attribute at slot <index> advances once
+ per vertex. If <divisor> is non-zero, the attribute advances once
+ per <divisor> instances of the primitives being rendered.
+ An attribute is referred to as "instanced" if its <divisor> value is
+ non-zero."
+
+ Replace the text describing DrawArrays and DrawElements in the
+ "Transferring Array Elements" subsection of 2.8, from the second paragraph
+ through the end of the section with the following:
+
+ "The command
+
+ void DrawArraysOneInstance( enum mode, int first, sizei count, int instance );
+
+ does not exist in the GL, but is used to describe functionality in
+ the rest of this section. This function constructs a sequence of
+ geometric primitives by transferring elements <first> through <first> +
+ <count> - 1 of each enabled non-instanced array to the GL. <mode>
+ specifies what kind of primitives are constructed, as defined in section
+ 2.6.1.
+
+ If an enabled vertex attribute array is instanced (it has a non-zero
+ attribute <divisor> as specified by VertexAttribDivisorANGLE), the element
+ that is transferred to the GL is given by:
+
+ floor( <instance> / <divisor> ).
+
+ If an array corresponding to a generic attribute required by a vertex shader
+ is not enabled, then the corresponding element is taken from the current
+ generic attribute state (see section 2.7).
+
+ If an array corresponding to a generic attribute required by a vertex shader
+ is enabled, the corresponding current generic attribute value is unaffected
+ by the execution of DrawArraysOneInstance.
+
+ Specifying <first> < 0 results in undefined behavior. Generating the error
+ INVALID_VALUE is recommended in this case.
+
+ The command
+
+ void DrawArrays( enum mode, int first, sizei count );
+
+ is equivalent to the command sequence
+
+ DrawArraysOneInstance(mode, first, count, 0);
+
+ The command
+
+ void DrawArraysInstancedANGLE(enum mode, int first, sizei count,
+ sizei primcount);
+
+ behaves identically to DrawArrays except that <primcount>
+ instances of the range of elements are executed, and the
+ <instance> advances for each iteration. Instanced attributes that
+ have <divisor> N, (where N > 0, as specified by
+ VertexAttribDivisorANGLE) advance once every N instances.
+
+ It has the same effect as:
+
+ if (mode, count, or primcount is invalid)
+ generate appropriate error
+ else {
+ for (i = 0; i < primcount; i++) {
+ DrawArraysOneInstance(mode, first, count, i);
+ }
+ }
+
+ The command
+
+ void DrawElementsOneInstance( enum mode, sizei count, enum type,
+ void *indices, int instance );
+
+ does not exist in the GL, but is used to describe functionality in
+ the rest of this section. This command constructs a sequence of
+ geometric primitives by successively transferring the <count> elements
+ whose indices are stored in the currently bound element array buffer
+ (see section 2.9.2) at the offset defined by <indices> to the GL.
+ The <i>-th element transferred by DrawElementsOneInstance will be taken
+ from element <indices>[i] of each enabled non-instanced array.
+ <type> must be one of UNSIGNED_BYTE, UNSIGNED_SHORT, or UNSIGNED_INT,
+ indicating that the index values are of GL type ubyte, ushort, or uint
+ respectively. <mode> specifies what kind of primitives are constructed,
+ as defined in section 2.6.1.
+
+ If an enabled vertex attribute array is instanced (it has a non-zero
+ attribute <divisor> as specified by VertexAttribDivisorANGLE), the element
+ that is transferred to the GL is given by:
+
+ floor( <instance> / <divisor> );
+
+ If an array corresponding to a generic attribute required by a vertex
+ shader is not enabled, then the corresponding element is taken from the
+ current generic attribute state (see section 2.7). Otherwise, if an array
+ is enabled, the corresponding current generic attribute value is
+ unaffected by the execution of DrawElementsOneInstance.
+
+ The command
+
+ void DrawElements( enum mode, sizei count, enum type,
+ const void *indices);
+
+ behaves identically to DrawElementsOneInstance with the <instance>
+ parameter set to zero; the effect of calling
+
+ DrawElements(mode, count, type, indices);
+
+ is equivalent to the command sequence:
+
+ if (mode, count or type is invalid )
+ generate appropriate error
+ else
+ DrawElementsOneInstance(mode, count, type, indices, 0);
+
+ The command
+
+ void DrawElementsInstancedANGLE(enum mode, sizei count, enum type,
+ const void *indices, sizei primcount);
+
+ behaves identically to DrawElements except that <primcount>
+ instances of the set of elements are executed and the instance
+ advances between each set. Instanced attributes are advanced as they do
+ during the execution of DrawArraysInstancedANGLE. It has the same effect as:
+
+ if (mode, count, primcount, or type is invalid )
+ generate appropriate error
+ else {
+ for (int i = 0; i < primcount; i++) {
+ DrawElementsOneInstance(mode, count, type, indices, i);
+ }
+ }
+
+ If the number of supported generic vertex attributes (the value of
+ MAX_VERTEX_ATTRIBS) is <n>, then the client state required to implement
+ vertex arrays consists of <n> boolean values, <n> memory pointers, <n>
+ integer stride values, <n> symbolic constants representing array types,
+ <n> integers representing values per element, <n> boolean values
+ indicating normalization, and <n> integers representing vertex attribute
+ divisors.
+
+ In the initial state, the boolean values are each false, the memory
+ pointers are each NULL, the strides are each zero, the array types are
+ each FLOAT, the integers representing values per element are each four,
+ and the divisors are each zero."
+
+Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)
+
+ None
+
+Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment
+Operations and the Framebuffer)
+
+ None
+
+Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions)
+
+ None
+
+Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State
+Requests)
+
+ In section 6.1.8, add VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE to the list of
+ pnames accepted by GetVertexAttribfv and GetVertexAttribiv.
+
+Additions to the AGL/EGL/GLX/WGL Specifications
+
+ None
+
+Dependencies on OES_element_index_uint
+
+ If OES_element_index_uint is not supported, removed all references
+ to UNSIGNED_INT indices and the associated GL data type uint in
+ the description of DrawElementsOneInstance.
+
+Errors
+
+ INVALID_VALUE is generated by VertexAttribDivisorANGLE if <index>
+ is greater than or equal to MAX_VERTEX_ATTRIBS.
+
+ INVALID_ENUM is generated by DrawElementsInstancedANGLE if <type> is
+ not one of UNSIGNED_BYTE, UNSIGNED_SHORT or UNSIGNED_INT.
+
+ INVALID_VALUE is generated by DrawArraysInstancedANGLE if <first>,
+ <count>, or <primcount> is less than zero.
+
+ INVALID_ENUM is generated by DrawArraysInstancedANGLE or
+ DrawElementsInstancedANGLE if <mode> is not one of the modes described in
+ section 2.6.1.
+
+ INVALID_VALUE is generated by DrawElementsInstancedANGLE if <count> or
+ <primcount> is less than zero.
+
+ INVALID_OPERATION is generated by DrawArraysInstancedANGLE or
+ DrawElementsInstancedANGLE if there is not at least one enabled
+ vertex attribute array that has a <divisor> of zero and is bound to an
+ active generic attribute value in the program used for the draw command.
+
+New State
+
+ Changes to table 6.7, p. 268 (Vertex Array Data)
+
+ Initial
+ Get Value Type Get Command Value Description Sec.
+ --------- ----- ----------- ------- ----------- ----
+ VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 8*xZ+ GetVertexAttrib 0 Instance Divisor 2.8
+
+Issues
+
+ 1) Should vertex attribute zero be instance-able?
+
+ Resolved: Yes.
+ Discussion: In Direct3D 9 stream 0 must be specified as indexed data
+ and it cannot be instanced. In ANGLE we can work around this by
+ remapping any other stream that does have indexed data (ie a zero
+ attribute divisor) to stream 0 in D3D9. This works because the HLSL
+ vertex shader matches attributes against the stream by using the
+ shader semantic index.
+
+ 2) Can all vertex attributes be instanced simultaneously?
+
+ Resolved: No
+ Discussion: In rare cases it is possible for no attribute to have a
+ divisor of 0, meaning that all attributes are instanced and none of
+ them are regularly indexed. This in turn means each instance can only
+ have a single position element, and so it only actually renders
+ something when rendering point primitives. This is not a very
+ meaningful way of using instancing (which is likely why D3D restricts
+ stream 0 to be indexed regularly for position data in the first place).
+ We could implement it by drawing these points one at a time (essentially
+ emulating instancing), but it would not be very efficient and there
+ seems to be little-to-no value in doing so.
+
+ If all of the enabled vertex attribute arrays that are bound to active
+ generic attributes in the program have a non-zero divisor, the draw
+ call should return INVALID_OPERATION.
+
+ 3) Direct3D 9 only supports instancing for DrawIndexedPrimitive which
+ corresponds to DrawElementsInstanced. Should we support
+ DrawArraysInstanced?
+
+ Resolved: Yes
+ Discussion: This can be supported easily enough by simply manufacturing
+ a linear index buffer of sufficient size and using that to do indexed
+ D3D9 drawing.
+
+ 4) How much data is needed in a buffer for an instanced attribute?
+
+ Resolved: Where stride is the value passed to VertexAttribPointer:
+
+ if stride > 0
+ size = stride * ceil(primcount / divisor);
+ else
+ size = elementsize * ceil(primcount / divisor);
+
+Revision History
+
+ #3 February 8, 2012 dgkoch
+ - clarify Issue 3 and the error condition for no indexed attributes
+ #2 January 24, 2012 dgkoch
+ - fix typos, add clarifications, and more errors
+ #1 January 17, 2012 dgkoch
+ - initial GLES2 version from ARB_instanced_arrays
diff --git a/extensions/ANGLE_pack_reverse_row_order.txt b/extensions/ANGLE_pack_reverse_row_order.txt
new file mode 100644
index 00000000..6ec06491
--- /dev/null
+++ b/extensions/ANGLE_pack_reverse_row_order.txt
@@ -0,0 +1,168 @@
+Name
+
+ ANGLE_pack_reverse_row_order
+
+Name Strings
+
+ GL_ANGLE_pack_reverse_row_order
+
+Contact
+
+ Daniel Koch, TransGaming (daniel 'at' transgaming.com)
+
+Contributors
+
+ Brian Salomon
+ Daniel Koch
+
+Status
+
+ Implemented in ANGLE ES2
+
+Version
+
+ Last Modified Date: February 22, 2011
+ Author Revision: 22
+
+Number
+
+ OpenGL ES Extension #110
+
+Dependencies
+
+ OpenGL 1.5 or OpenGL ES 1.0 are required.
+
+ Some of the functionality of this extension is not supported
+ when implemented against OpenGL ES.
+
+ EXT_texture_rg interacts with this extension.
+
+ The extension is written against the OpenGL 3.2 Specification
+ (Core Profile).
+
+Overview
+
+ This extension introduces a mechanism to allow reversing the order
+ in which image rows are written into a pack destination. This
+ effectively allows an application to flip the results of a ReadPixels
+ in the y direction operation without having to render upside down.
+
+ The coordinate system of OpenGL is vertically reversed in comparison to a
+ number of other graphics systems such as native windowing APIs. Applications
+ that perform ReadPixels may have to either render to an intermediate color
+ buffer before calling ReadPixels or perform a flip in software after
+ ReadPixels. In some systems the GL can perform the row reversal during
+ ReadPixels without incurring additional cost.
+
+IP Status
+
+ No known IP claims.
+
+New Procedures and Functions
+
+ None
+
+New Types
+
+ None
+
+New Tokens
+
+ Accepted by the <pname> parameter of PixelStore{if}, GetIntegerv(),
+ GetBooleanv(), and GetFloatv():
+
+ PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4
+
+Additions to Chapter 3 of the OpenGL 3.2 Specification (Rasterization)
+
+ In Section 4.3.1 (Reading Pixels) add a row to table 4.7:
+
+ +------------------------------+---------+---------------+-------------+
+ | Parameter Name | Type | Initial Value | Valid Range |
+ +------------------------------+---------+---------------+-------------+
+ | PACK_REVERSE_ROW_ORDER_ANGLE | boolean | FALSE | TRUE/FALSE |
+ +------------------------------+---------+---------------+-------------+
+
+ In Section 4.3.1 (Reading Pixels) modify the second paragraph of subsection
+ "Placement in Pixel Pack Buffer or Client Memory" to read:
+
+ When PACK_REVERSE_ROW_ORDER_ANGLE is FALSE groups of elements are placed
+ in memory just as they are taken from memory when transferring pixel
+ rectangles to the GL. That is, the ith group of the jth row
+ (corresponding to the ith pixel in the jth row) is placed in memory just
+ where the ith group of the jth row would be taken from when transferring
+ pixels. See Unpacking under section 3.7.2. The only difference is that
+ the storage mode parameters whose names begin with PACK_ are used
+ instead of those whose names begin with UNPACK_. If the format is RED,
+ GREEN, BLUE, or ALPHA, only the corresponding single element is written.
+ Likewise if the format is RG, RGB, or BGR, only the corresponding two or
+ three elements are written. Otherwise all the elements of each group are
+ written. When PACK_REVERSE_ROW_ORDER_ANGLE is TRUE the order of the rows
+ of elements is reversed before the data is packed. That is, the element
+ corresponding to pixel (x, y + height - 1) becomes the first element
+ packed, followed by (x + 1, y + height - 1), etc. Otherwise, pixel data
+ is packed in the same manner as when PACK_REVERSE_ROW_ORDER_ANGLE is
+ FALSE.
+
+Additions to Chapter 6 of the OpenGL 3.2 Specification (State and State Requests)
+
+ In Section 6.1.4 add the following sentence to the fifth paragraph
+ (beginning with "For three-dimensional and two-dimensional array
+ textures..."):
+ When PACK_REVERSE_ROW_ORDER_ANGLE is TRUE the order of rows within
+ each image are reversed without reordering the images themselves.
+
+Dependencies on OpenGL ES
+
+ If implemented for OpenGL ES, this extension behaves as specified, except:
+
+ -Delete all references to formats RED, GREEN, BLUE, RG, and BGR.
+
+ -The language about image order in Section 6.1.4 does not apply as OpenGL ES
+ does not have GetTexImage.
+
+Dependencies on EXT_texture_rg
+
+ If EXT_texture_rg is present reinsert language about formats RED and RG
+ into the OpenGL ES 2.0 specification.
+
+Errors
+
+ None
+
+New State
+ Initial
+ Get Value Type Get Command Value Description Sec.
+ --------- ---- ----------- ------- ----------- ----
+ PACK_REVERSE_ROW_ORDER_ANGLE B GetIntegerv FALSE Pixel pack row order reversal 4.3.1
+
+New Implementation Dependent State
+
+ None
+
+Issues
+
+ None
+
+Sample Code
+
+ /* Allocate space to hold the pixel data */
+ const GLvoid* pixels = malloc(width * height * 4);
+
+ /* Bind the framebuffer object to be read */
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
+
+ /* Enable row order reversal */
+ glPixelStore(GL_PACK_REVERSE_ROW_ORDER_ANGLE, TRUE);
+
+ /* The pixel data stored in pixels will be in top-down order, ready for
+ * use with a windowing system API that expects this order.
+ */
+ glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+Revision History
+
+ Revision 1, 2011/11/22 (Brian Salomon)
+ - First version
+ Revision 2, 2012/02/22 (dgkoch)
+ - prepare for publishing
diff --git a/extensions/ANGLE_program_binary.txt b/extensions/ANGLE_program_binary.txt
new file mode 100644
index 00000000..67550bc1
--- /dev/null
+++ b/extensions/ANGLE_program_binary.txt
@@ -0,0 +1,94 @@
+Name
+
+ ANGLE_program_binary
+
+Name Strings
+
+ GL_ANGLE_program_binary
+
+Contributors
+
+ Alastair Patrick, Google Inc.
+ Daniel Koch, TransGaming Inc.
+
+Contact
+
+ Alastair Patrick, Google Inc. (apatrick 'at' google 'dot' com)
+
+Status
+
+ Under development.
+
+Version
+
+ Last Modifed Date: June 6, 2012
+ Revision: #1
+
+Number
+
+ TBD
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+ OES_get_program_binary is required.
+ This extension is written against the OpenGL ES 2.0.25 specification.
+
+Overview
+
+ This extension makes available a program binary format,
+ PROGRAM_BINARY_ANGLE. It enables retrieving and loading of pre-linked
+ ANGLE program objects.
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ Accepted by the <binaryFormat> parameter of ProgramBinaryOES:
+
+ PROGRAM_BINARY_ANGLE 0x93A6
+
+Additions to Chapter 2 of the OpenGL-ES 2.0 Specification (OpenGL Operation)
+
+ Add the following paragraph to the end of section 2.15.4, Program Binaries:
+
+ "PROGRAM_BINARY_ANGLE, returned in the list of PROGRAM_BINARY_FORMATS_OES,
+ is a format that may be loaded into a program object via ProgramBinaryOES."
+
+Additions to Chapter 3 of the OpenGL ES 2.0 specification (Rasterizatoin)
+
+ None.
+
+Additions to Chapter 4 of the OpenGL ES 2.0 specification (Per-Fragment
+Operations and the Framebuffer)
+
+ None.
+
+Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special
+Functions)
+
+ None.
+
+Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State
+Requests)
+
+ None.
+
+Errors
+
+ None
+
+New State
+
+ None.
+
+Issues
+
+ None
+
+Revision History
+
+ 06/06/2012 apatrick intial revision
+
diff --git a/extensions/ANGLE_texture_compression_dxt.txt b/extensions/ANGLE_texture_compression_dxt.txt
new file mode 100644
index 00000000..0e844bfe
--- /dev/null
+++ b/extensions/ANGLE_texture_compression_dxt.txt
@@ -0,0 +1,163 @@
+Name
+
+ ANGLE_texture_compression_dxt
+
+Name Strings
+
+ GL_ANGLE_texture_compression_dxt1
+ GL_ANGLE_texture_compression_dxt3
+ GL_ANGLE_texture_compression_dxt5
+
+Contributors
+
+ Gregg Tavares, Google Inc.
+ Daniel Koch, TransGaming Inc.
+ Al Patrick, Google Inc.
+
+Contacts
+
+ Gregg Tavares, Google Inc. (gman 'at' google 'dot' com)
+
+Status
+
+ Implemented in ANGLE ES2
+
+Version
+
+ Last Modified Date: Sept 22, 2012
+ Author Revision: 2
+
+Number
+
+ OpenGL ES Extension #111
+
+Dependencies
+
+ Requires OpenGL ES 1.0.
+
+ The extension is written against the OpenGL ES 2.0 specification.
+
+Overview
+
+ These extensions are exactly the same as EXT_texture_compression_dxt1
+ except they additionally expose the COMPRESSED_RGBA_S3TC_DXT3_ANGLE and
+ COMPRESSED_RGBA_S3TC_DXT5_ANGLE formats and have a size restrictions
+ such that the size must be a multiple of four (except for mip levels
+ where the dimensions are either 2 or 1).
+
+ See EXT_texture_compression_dxt1 for the full list of changes. Also
+ see EXT_texture_compression_s3tc for a description of the formats.
+
+IP Status
+
+ A license to the S3TC Intellectual Property may be necessary for
+ implementation of this extension. You should consult with your
+ Attorney to determine the need for a license.
+
+New Procedures and Functions
+
+ None.
+
+New Types
+
+ None.
+
+New Tokens
+
+ Accepted by the <internalformat> parameter of CompressedTexImage2D
+ and the <format> parameter of CompressedTexSubImage2D:
+
+ COMPRESSED_RGB_S3TC_DXT1_ANGLE 0x83F0
+ COMPRESSED_RGBA_S3TC_DXT1_ANGLE 0x83F1
+ COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2
+ COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3
+
+Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)
+
+ Add the following to Section 3.7.3 (Compressed Texture Images)
+ (at the end of the description of the CompressedTexImage2D command):
+
+ Compressed Internal Format Base Internal Format
+ ========================== ====================
+ COMPRESSED_RGB_S3TC_DXT1_ANGLE RGB
+ COMPRESSED_RGBA_S3TC_DXT1_ANGLE RGBA
+ COMPRESSED_RGBA_S3TC_DXT3_ANGLE RGBA
+ COMPRESSED_RGBA_S3TC_DXT5_ANGLE RGBA
+
+ Table 3.x: Specific Compressed Internal Formats
+
+ If <internalformat> is one of the S3TC formats listed in Table 3.x,
+ the compressed texture is stored in the appropriate S3TC compressed
+ texture format (see Appendix). The GL and the S3TC texture compression
+ algorithm support only 2D images without borders.
+
+ CompressedTexImage2D will produce the INVALID_OPERATION error when
+ <internalformat> is one of the values from Table 3.x under the following
+ conditions:
+
+ * <border> is non-zero.
+ * <width> is not one, two, or a multiple of four.
+ * <height> is not one, two, or a multiple of four.
+
+ Add the following to Section 3.7.3 (Compressed Texture Images)
+ (at the end of the description of the CompressedTexSubImage2D command):
+
+ If the internal format of the texture image being modified is listed
+ in Table 3.x, the texture is stored in the appropriate S3TC compressed
+ texture format (see Appendix). Since DXT/S3TC images are easily edited
+ along 4x4 texel boundaries, the limitations of CompressedTexSubImage2D
+ are relaxed. CompressedTexSubImage2D will result in an INVALID_OPERATION
+ error only if one of the following conditions occurs:
+
+ * <width> is not a multiple of four or equal to TEXTURE_WIDTH.
+ * <height> is not a multipls of four or equal to TEXTURE_HEIGHT.
+ * <xoffset> or <yoffset> is not a multiple of four.
+ * <format> does not match the internal format of the texture image
+ being modified.
+
+ The following restrictions at the end of section 3.7.3 do not apply
+ to S3TC DXT texture formats, since subimage modification is straightforward
+ as long as the subimage is properly aligned.
+
+Errors
+
+ INVALID_OPERATION is generated by CompressedTexImage2D if <internalformat>
+ is one of the compressed internal formats from Table 3.x and any of the
+ following apply:
+ - <border> is not equal to zero.
+ - <width> is not one, two, or a multiple of four.
+ - <height> is not one, two, or a multiple of four.
+
+ INVALID_OPERATION is generated by TexImage2D and CopyTexImage2D if
+ <internalformat> is one of the compressed internal formats from
+ Table 3.x.
+
+ INVALID_OPERATION is generated by TexSubImage2D and CopyTexSubImage2D
+ if the internal format of the texture currently bound to <target> is
+ one of the compressed internal formats from Table 3.x.
+
+ INVALID_OPERATION is generated by CompressedTexSubImage2D if <format>
+ is one of the compressed interal formats from Table 3.x and any of the
+ following apply:
+ - <width> is not a multiple of four or equal to TEXTURE_WIDTH;
+ - <height> is not a multiple of four or equal to TEXTURE_HEIGHT;
+ - <xoffset> or <yoffset> is not a multiple of four;
+ - <format> does not match the internal format of the texture image
+ being modified.
+
+New State
+
+ None.
+
+Appendix:
+
+ The format for the S3TC Compressed Texture Images Formats is documented
+ in the appendix of EXT_texture_compression_s3tc.
+
+Revision History
+
+ Revision 1, 2010/08/06 - gman
+ - Initial revision
+ Revision 2, 2012/09/22 - dgkoch
+ - Added DXT1 formats and documented multiple of 4 restriction.
+
diff --git a/extensions/ANGLE_texture_usage.txt b/extensions/ANGLE_texture_usage.txt
new file mode 100644
index 00000000..17936538
--- /dev/null
+++ b/extensions/ANGLE_texture_usage.txt
@@ -0,0 +1,202 @@
+Name
+
+ ANGLE_texture_usage
+
+Name Strings
+
+ GL_ANGLE_texture_usage
+
+Contributors
+
+ Nicolas Capens, TransGaming
+ Daniel Koch, TransGaming
+
+Contact
+
+ Daniel Koch, TransGaming (daniel 'at' transgaming.com)
+
+Status
+
+ Complete
+
+Version
+
+ Last Modified Date: November 10, 2011
+ Version: 2
+
+Number
+
+ OpenGL ES Extension #112
+
+Dependencies
+
+ This extension is written against the OpenGL ES 2.0 Specification.
+
+Overview
+
+ In some implementations it is advantageous to know the expected
+ usage of a texture before the backing storage for it is allocated.
+ This can help to inform the implementation's choice of format
+ and type of memory used for the allocation. If the usage is not
+ known in advance, the implementation essentially has to make a
+ guess as to how it will be used. If it is later proven wrong,
+ it may need to perform costly re-allocations and/or reformatting
+ of the texture data, resulting in reduced performance.
+
+ This extension adds a texture usage flag that is specified via
+ the TEXTURE_USAGE_ANGLE TexParameter. This can be used to
+ indicate that the application knows that this texture will be
+ used for rendering.
+
+IP Status
+
+ No known IP claims.
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ Accepted as a value for <pname> for the TexParameter{if} and
+ TexParameter{if}v commands and for the <value> parameter of
+ GetTexParameter{if}v:
+
+ TEXTURE_USAGE_ANGLE 0x93A2
+
+ Accepted as a value to <param> for the TexParameter{if} and
+ to <params> for the TexParameter{if}v commands with a <pname> of
+ TEXTURE_USAGE_ANGLE; returned as possible values for <data> when
+ GetTexParameter{if}v is queried with a <value> of TEXTURE_USAGE_ANGLE:
+
+ NONE 0x0000
+ FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3
+
+Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation)
+
+ None
+
+Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)
+
+ Add a new row to Table 3.10 (Texture parameters and their values):
+
+ Name | Type | Legal Values
+ ------------------------------------------------------------
+ TEXTURE_USAGE_ANGLE | enum | NONE, FRAMEBUFFER_ATTACHMENT_ANGLE
+
+ Add a new section 3.7.x (Texture Usage) before section 3.7.12 and
+ renumber the subsequent sections:
+
+ "3.7.x Texture Usage
+
+ Texture usage can be specified via the TEXTURE_USAGE_ANGLE value
+ for the <pname> argument to TexParameter{if}[v]. In order to take effect,
+ the texture usage must be specified before the texture contents are
+ defined either via TexImage2D or TexStorage2DEXT.
+
+ The usage values can impact the layout and type of memory used for the
+ texture data. Specifying incorrect usage values may result in reduced
+ functionality and/or significantly degraded performance.
+
+ Possible values for <params> when <pname> is TEXTURE_USAGE_ANGLE are:
+
+ NONE - the default. No particular usage has been specified and it is
+ up to the implementation to determine the usage of the texture.
+ Leaving the usage unspecified means that the implementation may
+ have to reallocate the texture data as the texture is used in
+ various ways.
+
+ FRAMEBUFFER_ATTACHMENT_ANGLE - this texture will be attached to a
+ framebuffer object and used as a desination for rendering or blits."
+
+ Modify section 3.7.12 (Texture State) and place the last 3 sentences
+ with the following:
+
+ "Next, there are the three sets of texture properties; each consists of
+ the selected minification and magnification filters, the wrap modes for
+ <s> and <t>, and the usage flags. In the initial state, the value assigned
+ to TEXTURE_MIN_FILTER is NEAREST_MIPMAP_LINEAR, and the value for
+ TEXTURE_MAG_FILTER is LINEAR. <s> and <t> wrap modes are both set to
+ REPEAT. The initial value for TEXTURE_USAGE_ANGLE is NONE."
+
+
+Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment
+Operations and the Framebuffer)
+
+ None
+
+Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special
+Functions):
+
+ None
+
+Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and
+State Requests)
+
+ None
+
+Dependencies on EXT_texture_storage
+
+ If EXT_texture_storage is not supported, omit any references to
+ TexStorage2DEXT.
+
+Errors
+
+ If TexParameter{if} or TexParamter{if}v is called with a <pname>
+ of TEXTURE_USAGE_ANGLE and the value of <param> or <params> is not
+ NONE or FRAMEBUFFER_ATTACHMENT_ANGLE the error INVALID_VALUE is
+ generated.
+
+Usage Example
+
+ /* create and bind texture */
+ glGenTextures(1, &texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ /* specify texture parameters */
+ glTexParameteri(GL_TEXTURE_2D, GL_*, ...); /* as before */
+
+ /* specify that we'll be rendering to the texture */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
+
+ glTexStorage2DEXT(GL_TEXTURE_2D, levels, ...); // Allocation
+ for(int level = 0; level < levels; ++level)
+ glTexSubImage2D(GL_TEXTURE_2D, level, ...); // Initialisation
+
+Issues
+
+ 1. Should there be a dynamic usage value?
+
+ DISCUSSION: We could accept a dynamic flag to indicate that a texture will
+ be updated frequently. We could map this to D3D9 dynamic textures. This would
+ allow us to avoid creating temporary surfaces when updating the texture.
+ However renderable textures cannot be dynamic in D3D9, which eliminates the
+ primary use case for this. Furthermore, the memory usage of dynamic textures
+ typically increases threefold when you lock it.
+
+ 2. Should the texture usage be an enum or a bitfield?
+
+ UNRESOLVED. Using a bitfield would allow combination of values to be specified.
+ On the other hand, if combinations are really required, additional <pnames>
+ could be added as necessary. Querying a bitfield via the GetTexParameter command
+ feels a bit odd.
+
+ 3. What should happen if TEXTURE_USAGE_ANGLE is set/changed after the texture
+ contents have been specified?
+
+ RESOLVED: It will have no effect. However, if the texture is redefined (for
+ example by TexImage2D) the new allocation will use the updated usage.
+ GetTexParameter is used to query the value of the TEXTURE_USAGE_ANGLE
+ state that was last set by TexParameter for the currently bound texture, or
+ the default value if it has never been set. There is no way to determine the
+ usage that was in effect at the time the texture was defined.
+
+Revision History
+
+ Rev. Date Author Changes
+ ---- ----------- --------- ----------------------------------------
+ 1 10 Nov 2011 dgkoch Initial revision
+ 2 10 Nov 2011 dgkoch Add overview
+
+
diff --git a/extensions/ANGLE_timer_query.txt b/extensions/ANGLE_timer_query.txt
new file mode 100644
index 00000000..3cc38582
--- /dev/null
+++ b/extensions/ANGLE_timer_query.txt
@@ -0,0 +1,591 @@
+Name
+
+ ANGLE_timer_query
+
+Name Strings
+
+ GL_ANGLE_timer_query
+
+Contributors
+
+ Contributors to ARB_occlusion_query
+ Contributors to EXT_timer_query
+ Contributors to ARB_timer_query
+ Ben Vanik, Google Inc.
+ Daniel Koch, TransGaming Inc.
+
+Contact
+
+ Ben Vanik, Google Inc. (benvanik 'at' google 'dot' com)
+
+Status
+
+ Draft
+
+Version
+
+ Last Modified Date: Apr 28, 2011
+ Author Revision: 1
+
+Number
+
+ OpenGL ES Extension #??
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+ The extension is written against the OpenGL ES 2.0 specification.
+
+Overview
+
+ Applications can benefit from accurate timing information in a number of
+ different ways. During application development, timing information can
+ help identify application or driver bottlenecks. At run time,
+ applications can use timing information to dynamically adjust the amount
+ of detail in a scene to achieve constant frame rates. OpenGL
+ implementations have historically provided little to no useful timing
+ information. Applications can get some idea of timing by reading timers
+ on the CPU, but these timers are not synchronized with the graphics
+ rendering pipeline. Reading a CPU timer does not guarantee the completion
+ of a potentially large amount of graphics work accumulated before the
+ timer is read, and will thus produce wildly inaccurate results.
+ glFinish() can be used to determine when previous rendering commands have
+ been completed, but will idle the graphics pipeline and adversely affect
+ application performance.
+
+ This extension provides a query mechanism that can be used to determine
+ the amount of time it takes to fully complete a set of GL commands, and
+ without stalling the rendering pipeline. It uses the query object
+ mechanisms first introduced in the occlusion query extension, which allow
+ time intervals to be polled asynchronously by the application.
+
+IP Status
+
+ No known IP claims.
+
+New Procedures and Functions
+
+ void GenQueriesANGLE(sizei n, uint *ids);
+ void DeleteQueriesANGLE(sizei n, const uint *ids);
+ boolean IsQueryANGLE(uint id);
+ void BeginQueryANGLE(enum target, uint id);
+ void EndQueryANGLE(enum target);
+ void QueryCounterANGLE(uint id, enum target);
+ void GetQueryivANGLE(enum target, enum pname, int *params);
+ void GetQueryObjectivANGLE(uint id, enum pname, int *params);
+ void GetQueryObjectuivANGLE(uint id, enum pname, uint *params);
+ void GetQueryObjecti64vANGLE(uint id, enum pname, int64 *params);
+ void GetQueryObjectui64vANGLE(uint id, enum pname, uint64 *params);
+
+New Tokens
+
+ Accepted by the <pname> parameter of GetQueryivANGLE:
+
+ QUERY_COUNTER_BITS_ANGLE 0x8864
+ CURRENT_QUERY_ANGLE 0x8865
+
+ Accepted by the <pname> parameter of GetQueryObjectivANGLE,
+ GetQueryObjectuivANGLE, GetQueryObjecti64vANGLE, and
+ GetQueryObjectui64vANGLE:
+
+ QUERY_RESULT_ANGLE 0x8866
+ QUERY_RESULT_AVAILABLE_ANGLE 0x8867
+
+ Accepted by the <target> parameter of BeginQueryANGLE, EndQueryANGLE, and
+ GetQueryivANGLE:
+
+ TIME_ELAPSED_ANGLE 0x88BF
+
+ Accepted by the <target> parameter of GetQueryivANGLE and
+ QueryCounterANGLE:
+
+ TIMESTAMP_ANGLE 0x8E28
+
+Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation)
+
+ (Modify table 2.1, Correspondence of command suffix letters to GL argument)
+ Add two new types:
+
+ Letter Corresponding GL Type
+ ------ ---------------------
+ i64 int64ANGLE
+ ui64 uint64ANGLE
+
+ (Modify table 2.2, GL data types) Add two new types:
+
+ GL Type Minimum Bit Width Description
+ ------- ----------------- -----------------------------
+ int64ANGLE 64 Signed 2's complement integer
+ uint64ANGLE 64 Unsigned binary integer
+
+Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions)
+
+ Add a new section 5.3 "Timer Queries":
+
+ "5.3 Timer Queries
+
+ Timer queries use query objects to track the amount of time needed to
+ fully complete a set of GL commands, or to determine the current time
+ of the GL.
+
+ Timer queries are associated with query objects. The command
+
+ void GenQueriesANGLE(sizei n, uint *ids);
+
+ returns <n> previously unused query object names in <ids>. These
+ names are marked as used, but no object is associated with them until
+ the first time they are used by BeginQueryANGLE. Query objects contain
+ one piece of state, an integer result value. This result value is
+ initialized to zero when the object is created. Any positive integer
+ except for zero (which is reserved for the GL) is a valid query
+ object name.
+
+ Query objects are deleted by calling
+
+ void DeleteQueriesANGLE(sizei n, const uint *ids);
+
+ <ids> contains <n> names of query objects to be deleted. After a
+ query object is deleted, its name is again unused. Unused names in
+ <ids> are silently ignored.
+ If an active query object is deleted its name immediately becomes unused,
+ but the underlying object is not deleted until it is no longer active.
+
+ A timer query can be started and finished by calling
+
+ void BeginQueryANGLE(enum target, uint id);
+ void EndQueryANGLE(enum target);
+
+ where <target> is TIME_ELAPSED_ANGLE. If BeginQueryANGLE is called
+ with an unused <id>, that name is marked as used and associated with
+ a new query object.
+
+ If BeginQueryANGLE is called with an <id> of zero, if the active query
+ object name for <target> is non-zero, if <id> is the name of an existing
+ query object whose type does not match <target>, or if <id> is the active
+ query object name for any query type, the error INVALID_OPERATION is
+ generated. If EndQueryANGLE is called while no query with the same target
+ is in progress, an INVALID_OPERATION error is generated.
+
+ When BeginQueryANGLE and EndQueryANGLE are called with a <target> of
+ TIME_ELAPSED_ANGLE, the GL prepares to start and stop the timer used for
+ timer queries. The timer is started or stopped when the effects from all
+ previous commands on the GL client and server state and the framebuffer
+ have been fully realized. The BeginQueryANGLE and EndQueryANGLE commands
+ may return before the timer is actually started or stopped. When the timer
+ query timer is finally stopped, the elapsed time (in nanoseconds) is
+ written to the corresponding query object as the query result value, and
+ the query result for that object is marked as available.
+
+ If the elapsed time overflows the number of bits, <n>, available to hold
+ elapsed time, its value becomes undefined. It is recommended, but not
+ required, that implementations handle this overflow case by saturating at
+ 2^n - 1.
+
+ The necessary state is a single bit indicating whether an timer
+ query is active, the identifier of the currently active timer
+ query, and a counter keeping track of the time that has passed.
+
+ When the command
+
+ void QueryCounterANGLE(uint id, enum target);
+
+ is called with <target> TIMESTAMP_ANGLE, the GL records the current time
+ into the corresponding query object. The time is recorded after all
+ previous commands on the GL client and server state and the framebuffer
+ have been fully realized. When the time is recorded, the query result for
+ that object is marked available. QueryCounterANGLE timer queries can be
+ used within a BeginQueryANGLE / EndQueryANGLE block where the <target> is
+ TIME_ELAPSED_ANGLE and it does not affect the result of that query object.
+ The error INVALID_OPERATION is generated if the <id> is already in use
+ within a BeginQueryANGLE/EndQueryANGLE block."
+
+Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State
+Requests)
+
+ Add a new section 6.1.9 "Timer Queries":
+
+ "The command
+
+ boolean IsQueryANGLE(uint id);
+
+ returns TRUE if <id> is the name of a query object. If <id> is zero,
+ or if <id> is a non-zero value that is not the name of a query
+ object, IsQueryANGLE returns FALSE.
+
+ Information about a query target can be queried with the command
+
+ void GetQueryivANGLE(enum target, enum pname, int *params);
+
+ <target> identifies the query target and can be TIME_ELAPSED_ANGLE or
+ TIMESTAMP_ANGLE for timer queries.
+
+ If <pname> is CURRENT_QUERY_ANGLE, the name of the currently active query
+ for <target>, or zero if no query is active, will be placed in <params>.
+
+ If <pname> is QUERY_COUNTER_BITS_ANGLE, the implementation-dependent number
+ of bits used to hold the query result for <target> will be placed in
+ <params>. The number of query counter bits may be zero, in which case
+ the counter contains no useful information.
+
+ For timer queries (TIME_ELAPSED_ANGLE and TIMESTAMP_ANGLE), if the number
+ of bits is non-zero, the minimum number of bits allowed is 30 which
+ will allow at least 1 second of timing.
+
+ The state of a query object can be queried with the commands
+
+ void GetQueryObjectivANGLE(uint id, enum pname, int *params);
+ void GetQueryObjectuivANGLE(uint id, enum pname, uint *params);
+ void GetQueryObjecti64vANGLE(uint id, enum pname, int64 *params);
+ void GetQueryObjectui64vANGLE(uint id, enum pname, uint64 *params);
+
+ If <id> is not the name of a query object, or if the query object
+ named by <id> is currently active, then an INVALID_OPERATION error is
+ generated.
+
+ If <pname> is QUERY_RESULT_ANGLE, then the query object's result
+ value is returned as a single integer in <params>. If the value is so
+ large in magnitude that it cannot be represented with the requested type,
+ then the nearest value representable using the requested type is
+ returned. If the number of query counter bits for target is zero, then
+ the result is returned as a single integer with the value zero.
+
+ There may be an indeterminate delay before the above query returns. If
+ <pname> is QUERY_RESULT_AVAILABLE_ANGLE, FALSE is returned if such a delay
+ would be required; otherwise TRUE is returned. It must always be true
+ that if any query object returns a result available of TRUE, all queries
+ of the same type issued prior to that query must also return TRUE.
+
+ Querying the state for a given timer query forces that timer query to
+ complete within a finite amount of time.
+
+ If multiple queries are issued on the same target and id prior to
+ calling GetQueryObject[u]i[64]vANGLE, the result returned will always be
+ from the last query issued. The results from any queries before the
+ last one will be lost if the results are not retrieved before starting
+ a new query on the same <target> and <id>."
+
+Errors
+
+ The error INVALID_VALUE is generated if GenQueriesANGLE is called where
+ <n> is negative.
+
+ The error INVALID_VALUE is generated if DeleteQueriesANGLE is called
+ where <n> is negative.
+
+ The error INVALID_OPERATION is generated if BeginQueryANGLE is called
+ when a query of the given <target> is already active.
+
+ The error INVALID_OPERATION is generated if EndQueryANGLE is called
+ when a query of the given <target> is not active.
+
+ The error INVALID_OPERATION is generated if BeginQueryANGLE is called
+ where <id> is zero.
+
+ The error INVALID_OPERATION is generated if BeginQueryANGLE is called
+ where <id> is the name of a query currently in progress.
+
+ The error INVALID_OPERATION is generated if BeginQueryANGLE is called
+ where <id> is the name of an existing query object whose type does not
+ match <target>.
+
+ The error INVALID_ENUM is generated if BeginQueryANGLE or EndQueryANGLE
+ is called where <target> is not TIME_ELAPSED_ANGLE.
+
+ The error INVALID_ENUM is generated if GetQueryivANGLE is called where
+ <target> is not TIME_ELAPSED_ANGLE or TIMESTAMP_ANGLE.
+
+ The error INVALID_ENUM is generated if GetQueryivANGLE is called where
+ <pname> is not QUERY_COUNTER_BITS_ANGLE or CURRENT_QUERY_ANGLE.
+
+ The error INVALID_ENUM is generated if QueryCounterANGLE is called where
+ <target> is not TIMESTAMP_ANGLE.
+
+ The error INVALID_OPERATION is generated if QueryCounterANGLE is called
+ on a query object that is already in use inside a
+ BeginQueryANGLE/EndQueryANGLE.
+
+ The error INVALID_OPERATION is generated if GetQueryObjectivANGLE,
+ GetQueryObjectuivANGLE, GetQueryObjecti64vANGLE, or
+ GetQueryObjectui64vANGLE is called where <id> is not the name of a query
+ object.
+
+ The error INVALID_OPERATION is generated if GetQueryObjectivANGLE,
+ GetQueryObjectuivANGLE, GetQueryObjecti64vANGLE, or
+ GetQueryObjectui64vANGLE is called where <id> is the name of a currently
+ active query object.
+
+ The error INVALID_ENUM is generated if GetQueryObjectivANGLE,
+ GetQueryObjectuivANGLE, GetQueryObjecti64vANGLE, or
+ GetQueryObjectui64vANGLE is called where <pname> is not
+ QUERY_RESULT_ANGLE or QUERY_RESULT_AVAILABLE_ANGLE.
+
+New State
+
+ (Add a new table 6.xx, "Query Operations")
+
+ Get Value Type Get Command Initial Value Description Sec
+ --------- ---- ----------- ------------- ----------- ------
+ - B - FALSE query active 5.3
+ CURRENT_QUERY_ANGLE Z+ GetQueryivANGLE 0 active query ID 5.3
+ QUERY_RESULT_ANGLE Z+ GetQueryObjectuivANGLE, 0 samples-passed count 5.3
+ GetQueryObjectui64vANGLE
+ QUERY_RESULT_AVAILABLE_ANGLE B GetQueryObjectivANGLE FALSE query result available 5.3
+
+New Implementation Dependent State
+
+ (Add the following entry to table 6.18):
+
+ Get Value Type Get Command Minimum Value Description Sec
+ -------------------------- ---- ----------- ------------- ---------------- ------
+ QUERY_COUNTER_BITS_ANGLE Z+ GetQueryivANGLE see 6.1.9 Number of bits in 6.1.9
+ query counter
+
+Examples
+
+ (1) Here is some rough sample code that demonstrates the intended usage
+ of this extension.
+
+ GLint queries[N];
+ GLint available = 0;
+ // timer queries can contain more than 32 bits of data, so always
+ // query them using the 64 bit types to avoid overflow
+ GLuint64ANGLE timeElapsed = 0;
+
+ // Create a query object.
+ glGenQueriesANGLE(N, queries);
+
+ // Start query 1
+ glBeginQueryANGLE(GL_TIME_ELAPSED_ANGLE, queries[0]);
+
+ // Draw object 1
+ ....
+
+ // End query 1
+ glEndQueryANGLE(GL_TIME_ELAPSED_ANGLE);
+
+ ...
+
+ // Start query N
+ glBeginQueryANGLE(GL_TIME_ELAPSED_ANGLE, queries[N-1]);
+
+ // Draw object N
+ ....
+
+ // End query N
+ glEndQueryANGLE(GL_TIME_ELAPSED_ANGLE);
+
+ // Wait for all results to become available
+ while (!available) {
+ glGetQueryObjectivANGLE(queries[N-1], GL_QUERY_RESULT_AVAILABLE_ANGLE, &available);
+ }
+
+ for (i = 0; i < N; i++) {
+ // See how much time the rendering of object i took in nanoseconds.
+ glGetQueryObjectui64vANGLE(queries[i], GL_QUERY_RESULT_ANGLE, &timeElapsed);
+
+ // Do something useful with the time. Note that care should be
+ // taken to use all significant bits of the result, not just the
+ // least significant 32 bits.
+ AdjustObjectLODBasedOnDrawTime(i, timeElapsed);
+ }
+
+ This example is sub-optimal in that it stalls at the end of every
+ frame to wait for query results. Ideally, the collection of results
+ would be delayed one frame to minimize the amount of time spent
+ waiting for the GPU to finish rendering.
+
+ (2) This example is basically the same as the example above but uses
+ QueryCounter instead.
+
+ GLint queries[N+1];
+ GLint available = 0;
+ // timer queries can contain more than 32 bits of data, so always
+ // query them using the 64 bit types to avoid overflow
+ GLuint64ANGLE timeStart, timeEnd, timeElapsed = 0;
+
+ // Create a query object.
+ glGenQueriesANGLE(N+1, queries);
+
+ // Query current timestamp 1
+ glQueryCounterANGLE(queries[0], GL_TIMESTAMP_ANGLE);
+
+ // Draw object 1
+ ....
+
+ // Query current timestamp N
+ glQueryCounterANGLE(queries[N-1], GL_TIMESTAMP_ANGLE);
+
+ // Draw object N
+ ....
+
+ // Query current timestamp N+1
+ glQueryCounterANGLE(queries[N], GL_TIMESTAMP_ANGLE);
+
+ // Wait for all results to become available
+ while (!available) {
+ glGetQueryObjectivANGLE(queries[N], GL_QUERY_RESULT_AVAILABLE_ANGLE, &available);
+ }
+
+ for (i = 0; i < N; i++) {
+ // See how much time the rendering of object i took in nanoseconds.
+ glGetQueryObjectui64vANGLE(queries[i], GL_QUERY_RESULT_ANGLE, &timeStart);
+ glGetQueryObjectui64vANGLE(queries[i+1], GL_QUERY_RESULT_ANGLE, &timeEnd);
+ timeElapsed = timeEnd - timeStart;
+
+ // Do something useful with the time. Note that care should be
+ // taken to use all significant bits of the result, not just the
+ // least significant 32 bits.
+ AdjustObjectLODBasedOnDrawTime(i, timeElapsed);
+ }
+
+Issues from EXT_timer_query
+
+ (1) What time interval is being measured?
+
+ RESOLVED: The timer starts when all commands prior to BeginQuery() have
+ been fully executed. At that point, everything that should be drawn by
+ those commands has been written to the framebuffer. The timer stops
+ when all commands prior to EndQuery() have been fully executed.
+
+ (2) What unit of time will time intervals be returned in?
+
+ RESOLVED: Nanoseconds (10^-9 seconds). This unit of measurement allows
+ for reasonably accurate timing of even small blocks of rendering
+ commands. The granularity of the timer is implementation-dependent. A
+ 32-bit query counter can express intervals of up to approximately 4
+ seconds.
+
+ (3) What should be the minimum number of counter bits for timer queries?
+
+ RESOLVED: 30 bits, which will allow timing sections that take up to 1
+ second to render.
+
+ (4) How are counter results of more than 32 bits returned?
+
+ RESOLVED: Via two new datatypes, int64ANGLE and uint64ANGLE, and their
+ corresponding GetQueryObject entry points. These types hold integer
+ values and have a minimum bit width of 64.
+
+ (5) Should the extension measure total time elapsed between the full
+ completion of the BeginQuery and EndQuery commands, or just time
+ spent in the graphics library?
+
+ RESOLVED: This extension will measure the total time elapsed between
+ the full completion of these commands. Future extensions may implement
+ a query to determine time elapsed at different stages of the graphics
+ pipeline.
+
+ (6) If multiple query types are supported, can multiple query types be
+ active simultaneously?
+
+ RESOLVED: Yes; an application may perform a timer query and another
+ type of query simultaneously. An application can not perform multiple
+ timer queries or multiple queries of other types simultaneously. An
+ application also can not use the same query object for another query
+ and a timer query simultaneously.
+
+ (7) Do query objects have a query type permanently associated with them?
+
+ RESOLVED: No. A single query object can be used to perform different
+ types of queries, but not at the same time.
+
+ Having a fixed type for each query object simplifies some aspects of the
+ implementation -- not having to deal with queries with different result
+ sizes, for example. It would also mean that BeginQuery() with a query
+ object of the "wrong" type would result in an INVALID_OPERATION error.
+
+ UPDATE: This resolution was relevant for EXT_timer_query and OpenGL 2.0.
+ Since EXT_transform_feedback has since been incorporated into the core,
+ the resolution is that BeginQuery will generate error INVALID_OPERATION
+ if <id> represents a query object of a different type.
+
+ (8) How predictable/repeatable are the results returned by the timer
+ query?
+
+ RESOLVED: In general, the amount of time needed to render the same
+ primitives should be fairly constant. But there may be many other
+ system issues (e.g., context switching on the CPU and GPU, virtual
+ memory page faults, memory cache behavior on the CPU and GPU) that can
+ cause times to vary wildly.
+
+ Note that modern GPUs are generally highly pipelined, and may be
+ processing different primitives in different pipeline stages
+ simultaneously. In this extension, the timers start and stop when the
+ BeginQuery/EndQuery commands reach the bottom of the rendering pipeline.
+ What that means is that by the time the timer starts, the GL driver on
+ the CPU may have started work on GL commands issued after BeginQuery,
+ and the higher pipeline stages (e.g., vertex transformation) may have
+ started as well.
+
+ (9) What should the new 64 bit integer type be called?
+
+ RESOLVED: The new types will be called GLint64ANGLE/GLuint64ANGLE. The new
+ command suffixes will be i64 and ui64. These names clearly convey the
+ minimum size of the types. These types are similar to the C99 standard
+ type int_least64_t, but we use names similar to the C99 optional type
+ int64_t for simplicity.
+
+Issues from ARB_timer_query
+
+ (10) What about tile-based implementations? The effects of a command are
+ not complete until the frame is completely rendered. Timing recorded
+ before the frame is complete may not be what developers expect. Also
+ the amount of time needed to render the same primitives is not
+ consistent, which conflicts with issue (8) above. The time depends on
+ how early or late in the scene it is placed.
+
+ RESOLVED: The current language supports tile-based rendering okay as it
+ is written. Developers are warned that using timers on tile-based
+ implementation may not produce results they expect since rendering is not
+ done in a linear order. Timing results are calculated when the frame is
+ completed and may depend on how early or late in the scene it is placed.
+
+ (11) Can the GL implementation use different clocks to implement the
+ TIME_ELAPSED and TIMESTAMP queries?
+
+ RESOLVED: Yes, the implemenation can use different internal clocks to
+ implement TIME_ELAPSED and TIMESTAMP. If different clocks are
+ used it is possible there is a slight discrepancy when comparing queries
+ made from TIME_ELAPSED and TIMESTAMP; they may have slight
+ differences when both are used to measure the same sequence. However, this
+ is unlikely to affect real applications since comparing the two queries is
+ not expected to be useful.
+
+Issues
+
+ (12) What should we call this extension?
+
+ RESOLVED: ANGLE_timer_query
+
+ (13) Why is this done as a separate extension instead of just supporting
+ ARB_timer_query?
+
+ ARB_timer_query is written against OpenGL 3.2, which includes a lot of
+ the required support for dealing with query objects. None of these
+ functions or tokens exist in OpenGL ES, and as such have to be added in
+ this specification.
+
+ (14) How does this extension differ from ARB_timer_query?
+
+ This extension contains most ARB_timer_query behavior unchanged as well
+ as a subset of the query support required to use it from the core
+ OpenGL 3.2 spec. It omits the glGetInteger(TIMESTAMP) functionality used to
+ query the current time on the GPU, but the behavior for all remaining
+ functionality taken from ARB_timer_query is the same.
+
+ (15) Are query objects shareable between multiple contexts?
+
+ RESOLVED: No. Query objects are lightweight and we normally share
+ large data across contexts. Also, being able to share query objects
+ across contexts is not particularly useful. In order to do the async
+ query across contexts, a query on one context would have to be finished
+ before the other context could query it.
+
+Revision History
+
+ Revision 1, 2011/04/28
+ - copied from revision 9 of ARB_timer_query and revision 7 of
+ ARB_occlusion_query
+ - removed language that was clearly not relevant to ES2
+ - rebased changes against the OpenGL ES 2.0 specification
diff --git a/extensions/ANGLE_translated_shader_source.txt b/extensions/ANGLE_translated_shader_source.txt
new file mode 100644
index 00000000..69161156
--- /dev/null
+++ b/extensions/ANGLE_translated_shader_source.txt
@@ -0,0 +1,118 @@
+Name
+
+ ANGLE_translated_shader_source
+
+Name Strings
+
+ GL_ANGLE_translated_shader_source
+
+Contributors
+
+ Daniel Koch, TransGaming Inc.
+ Gregg Tavares, Google Inc.
+ Kenneth Russell, Google Inc.
+ Zhenyao Mo, Google Inc.
+
+Contact
+
+ Zhenyao Mo, Google Inc. (zmo 'at' google 'dot' com)
+
+Status
+
+ Implemented in ANGLE ES2
+
+Version
+
+ Last Modified Date: October 5, 2011
+ Author Revision: 2
+
+Number
+
+ OpenGL ES Extension #113
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+ The extension is written against the OpenGL ES 2.0 specification.
+
+Overview
+
+ WebGL uses the GLSL ES 2.0 spec on all platforms, and translates these
+ shaders to the host platform's native language (HLSL, GLSL, and even GLSL
+ ES). For debugging purposes, it is useful to be able to examine the shader
+ after translation.
+
+ This extension addes a new function to query the translated shader source,
+ and adds a new enum for GetShaderiv's <pname> parameter to query the
+ translated shader source length.
+
+IP Status
+
+ No known IP claims.
+
+New Types
+
+ None
+
+New Procedures and Functions
+
+ void GetTranslatedShaderSourceANGLE(uint shader, sizei bufsize,
+ sizei* length, char* source);
+
+New Tokens
+
+ Accepted by the <pname> parameter of GetShaderiv:
+
+ TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0
+
+Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State
+Requests)
+
+ Append in the end of the fourth paragraph of section 6.1.8 (Shader and
+ Program Queries):
+
+ " If <pname> is TRANSLATED_SHADER_LENGTH_ANGLE, the length of the translated
+ source string, including a null terminator, is returned. If no source has
+ been defined, CompileShader has not been called, or the translation has
+ failed for <shader>, zero is returned."
+
+ Append after the last paragraph of section 6.1.8 (Shader and Program
+ Queries):
+
+ "The command
+
+ void GetTranslatedShaderSourceANGLE( uint shader, sizei bufSize,
+ sizei *length, char *source );
+
+ returns in <source> the string making up the translated source code for
+ the shader object <shader>. The string <source> will be null terminated.
+ The actual number of characters written into <source>, excluding the null
+ terminator, is returned in <length>. If <length> is NULL, no length is
+ returned. The maximum number of characters that may be written into
+ <source>, including the null terminator, is specified by <bufSize>. The
+ string <source> is the translated string of a concatenation of the strings
+ passed to the GL using ShaderSource. The length of this translated string
+ is given by TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE, which can be queried
+ with GetShaderiv.
+
+ If no source has been defined, CompileShader has not been called, or the
+ translation has failed for <shader>, zero is returned for <length>, and
+ an empty string is returned for <source>.
+
+ If the value of SHADER_COMPILER is not TRUE, then the error INVALID_-
+ OPERATION is generated."
+
+Issues
+
+ 1) What enum value should be used for TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE?
+
+ RESOLVED: The first draft used a temporary enum value. This been replaced
+ with a enum allocated from the ANGLE range of GL enums.
+
+Revision History
+
+ Revision 1, 2011/09/29, zmo
+ - first draft
+ Revision 2, 2011/10/05, dgkoch
+ - assigned enum
diff --git a/extensions/EGL_ANGLE_d3d_share_handle_client_buffer.txt b/extensions/EGL_ANGLE_d3d_share_handle_client_buffer.txt
new file mode 100644
index 00000000..d54eaca6
--- /dev/null
+++ b/extensions/EGL_ANGLE_d3d_share_handle_client_buffer.txt
@@ -0,0 +1,98 @@
+Name
+
+ ANGLE_d3d_share_handle_client_buffer
+
+Name Strings
+
+ EGL_ANGLE_d3d_share_handle_client_buffer
+
+Contributors
+
+ John Bauman
+ Alastair Patrick
+ Daniel Koch
+
+Contacts
+
+ John Bauman, Google Inc. (jbauman 'at' chromium.org)
+
+Status
+
+ Complete
+ Implemented (ANGLE r650)
+
+Version
+
+ Version 3, May 12, 2011
+
+Number
+
+ EGL Extension #??
+
+Dependencies
+
+ Requires the EGL_ANGLE_surface_d3d_texture_2d_share_handle extension.
+
+ This extension is written against the wording of the EGL 1.4
+ Specification.
+
+Overview
+
+ This extension allows creating EGL surfaces from handles to textures
+ shared from the Direct3D API or from
+ EGL_ANGLE_surface_texture_2d_share_handle.
+
+New Types
+
+ None
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ Accepted in the <buftype> parameter of eglCreatePbufferFromClientBuffer:
+
+ EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
+
+Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
+
+ Replace the last sentence of paragraph 1 of Section 3.5.3 with the
+ following text.
+ "Currently, the only client API resources which may be bound in this
+ fashion are OpenVG VGImage objects and Direct3D share handles."
+
+ Replace the last sentence of paragraph 2 ("To bind a client API...") of
+ Section 3.5.3 with the following text.
+ "When <buftype> is EGL_OPENVG_IMAGE, the width and height of the pbuffer
+ are determined by the width and height of <buffer>. When <buftype> is
+ EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, the width and height are specified
+ using EGL_WIDTH and EGL_HEIGHT, or else they default to zero. The width
+ and height must match the dimensions of the texture which the share handle
+ was created from or else an EGL_BAD_ALLOC error is generated."
+
+ Replace the third paragraph of Section 3.5.3 with the following text.
+ "<buftype> specifies the type of buffer to be bound. The only allowed values
+ of <buftype> are EGL_OPENVG_IMAGE and
+ EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE".
+
+ Append the following text to the fourth paragraph of Section 3.5.3.
+ "When <buftype> is EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, <buffer> must be
+ a valid D3D share handle, cast into the type EGLClientBuffer. The handle
+ may be obtained from the Direct3D9Ex CreateTexture function, from DXGI's
+ GetSharedHandle method on an ID3D10Texture2D, or from the
+ EGL_ANGLE_surface_d3d_texture_2d_share_handle extension."
+
+Issues
+
+Revision History
+
+ Version 3, 2011/05/12
+ - publish
+
+ Version 2, 2011/05/03
+ - specify EGL_D3D_TEXTURE_2D_SHARE_HANDLE
+ - specify error if dimensions don't match
+
+ Version 1, 2011/04/12 - first draft.
diff --git a/extensions/EGL_ANGLE_direct3d_display.txt b/extensions/EGL_ANGLE_direct3d_display.txt
new file mode 100644
index 00000000..267ca9ce
--- /dev/null
+++ b/extensions/EGL_ANGLE_direct3d_display.txt
@@ -0,0 +1,68 @@
+Name
+
+ ANGLE_direct3d_display
+
+Name Strings
+
+ EGL_ANGLE_direct3d_display
+
+Contributors
+
+ Nicolas Capens
+ Shannon Woods
+
+Contacts
+
+ Shannon Woods, Google Inc. (shannonwoods 'at' chromium.org)
+
+Status
+
+ In progress
+
+Version
+
+ Version 1, May 15, 2013
+
+Number
+
+ EGL Extension #??
+
+Dependencies
+
+ This extension is written against the wording of the EGL 1.4
+ Specification.
+
+Overview
+
+ This extension allows for specifying the behavior of the renderer backing the display.
+
+New Types
+
+ None
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE (EGLNativeDisplayType)-2
+ EGL_D3D11_ONLY_DISPLAY_ANGLE (EGLNativeDisplayType)-3
+
+Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
+
+ Add before the last sentence of the first paragraph of section 3.2,
+ "Initialization":
+
+ "If <display_id> is EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE, the display returned
+ will be backed by a Direct3D 11 renderer if one is available, or by a
+ Direct3D 9 renderer otherwise. If <display_id> is EGL_D3D11_ONLY_DISPLAY_ANGLE,
+ the display returned will be backed by a Direct3D 11 renderer if one is
+ available, or will return NULL otherwise."
+
+Issues
+
+Revision History
+
+ Version 1, 2013/05/15 - First draft.
+
diff --git a/extensions/EGL_ANGLE_query_surface_pointer.txt b/extensions/EGL_ANGLE_query_surface_pointer.txt
new file mode 100644
index 00000000..75126fcb
--- /dev/null
+++ b/extensions/EGL_ANGLE_query_surface_pointer.txt
@@ -0,0 +1,88 @@
+Name
+
+ ANGLE_query_surface_pointer
+
+Name Strings
+
+ EGL_ANGLE_query_surface_pointer
+
+Contributors
+
+ Vladimir Vukicevic
+ Daniel Koch
+
+Contacts
+
+ Vladimir Vukicevic (vladimir 'at' pobox.com)
+
+Status
+
+ Complete
+ Implemented (ANGLE r558)
+
+Version
+
+ Version 3, February 11, 2011
+
+Number
+
+ EGL Extension #28
+
+Dependencies
+
+ This extension is written against the wording of the EGL 1.4
+ Specification.
+
+Overview
+
+ This extension allows querying pointer-sized surface attributes,
+ thus avoiding problems with coercing 64-bit pointers into a 32-bit
+ integer.
+
+New Types
+
+ None
+
+New Procedures and Functions
+
+ EGLBoolean eglQuerySurfacePointerANGLE(
+ EGLDisplay dpy,
+ EGLSurface surface,
+ EGLint attribute,
+ void **value);
+
+New Tokens
+
+ None
+
+Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
+
+ Add to the end of the paragraph starting with "To query an
+ attribute associated with an EGLSurface" in section 3.5.6,
+ "Surface Attributes":
+
+ "If the attribute type in table 3.5 is 'pointer', then
+ eglQuerySurface returns EGL_FALSE and an EGL_BAD_PARAMETER error
+ is generated. To query pointer attributes, call:
+
+ EGLBoolean eglQuerySurfacePointerANGLE(
+ EGLDisplay dpy,
+ EGLSurface surface,
+ EGLint attribute,
+ void **value);
+
+ eglQuerySurfacePointerANGLE behaves identically to eglQuerySurface,
+ except that only attributes of type 'pointer' can be queried.
+ If an attribute queried via eglQuerySurfacePointerANGLE is not
+ of type 'pointer', then eglQuerySurfacePointer returns EGL_FALSE
+ and an EGL_BAD_PARAMETER error is generated."
+
+Issues
+
+Revision History
+
+ Version 3, 2011/02/11 - publish
+
+ Version 2, 2010/12/21 - fix typos.
+
+ Version 1, 2010/12/07 - first draft.
diff --git a/extensions/EGL_ANGLE_software_display.txt b/extensions/EGL_ANGLE_software_display.txt
new file mode 100644
index 00000000..556e1bee
--- /dev/null
+++ b/extensions/EGL_ANGLE_software_display.txt
@@ -0,0 +1,65 @@
+Name
+
+ ANGLE_software_display
+
+Name Strings
+
+ EGL_ANGLE_software_display
+
+Contributors
+
+ John Bauman
+ Daniel Koch
+
+Contacts
+
+ John Bauman, Google Inc. (jbauman 'at' chromium.org)
+
+Status
+
+ In progress
+
+Version
+
+ Version 2, October 19, 2011
+
+Number
+
+ EGL Extension #??
+
+Dependencies
+
+ This extension is written against the wording of the EGL 1.4
+ Specification.
+
+Overview
+
+ This extension allows for receiving a device that uses software rendering.
+
+New Types
+
+ None
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ EGL_SOFTWARE_DISPLAY_ANGLE (EGLNativeDisplayType)-1
+
+Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
+
+ Add before the last sentence of the first paragraph of section 3.2,
+ "Initialization":
+
+ "If <display_id> is EGL_SOFTWARE_DISPLAY_ANGLE, a display that will render
+ everything in software will be returned."
+
+Issues
+
+Revision History
+
+ Version 1, 2011/07/12 - first draft.
+ Version 2, 2011/10/18 - add token definition
+
diff --git a/extensions/EGL_ANGLE_surface_d3d_texture_2d_share_handle.txt b/extensions/EGL_ANGLE_surface_d3d_texture_2d_share_handle.txt
new file mode 100644
index 00000000..917e4456
--- /dev/null
+++ b/extensions/EGL_ANGLE_surface_d3d_texture_2d_share_handle.txt
@@ -0,0 +1,95 @@
+Name
+
+ ANGLE_surface_d3d_texture_2d_share_handle
+
+Name Strings
+
+ EGL_ANGLE_surface_d3d_texture_2d_share_handle
+
+Contributors
+
+ Vladimir Vukicevic
+ Daniel Koch
+
+Contacts
+
+ Vladimir Vukicevic (vladimir 'at' pobox.com)
+
+Status
+
+ Complete
+ Implemented (ANGLE r558)
+
+Version
+
+ Version 2, December 21, 2010
+
+Number
+
+ EGL Extension #29
+
+Dependencies
+
+ Requires the EGL_ANGLE_query_surface_pointer extension.
+
+ This extension is written against the wording of the EGL 1.4
+ Specification.
+
+Overview
+
+ Some EGL implementations generate EGLSurface handles that are
+ backed by Direct3D 2D textures. For such surfaces, a D3D share
+ handle can be generated, allowing access to the same surface
+ from the Direct3D API.
+
+New Types
+
+ None
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ Accepted in the <attribute> parameter of eglQuerySurfacePointerANGLE:
+
+ EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
+
+Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
+
+ Add to table 3.5, "Queryable surface attributes and types":
+
+ Attribute Type Description
+ --------- ---- -----------
+ EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE pointer Direct3D share handle
+
+ Add before the last paragraph in section 3.5, "Surface attributes":
+
+ "Querying EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE returns a Direct3D
+ share handle, or NULL if a share handle for the surface is not
+ available. The share handle must be queried using
+ eglQuerySurfaceAttribPointerANGLE. Before using a Direct3D surface
+ created with this share handle, ensure that all rendering
+ to the EGLSurface with EGL client APIs has completed.
+
+ The Direct3D share handle may be passed as the pSharedHandle
+ parameter of the Direct3D9Ex CreateTexture function, or via the
+ Direct3D10 OpenSharedResource function. If used with Direct3D 9,
+ the level argument to CreateTexture must be 1, and the dimensions
+ must match the dimensions of the EGL surface. If used with
+ Direct3D 10, OpenSharedResource should be called with the
+ ID3D10Texture2D uuid to obtain an ID3D10Texture2D object.
+
+Issues
+
+Revision History
+
+ Version 3, 2011/02/11 - publish
+
+ Version 2, 2010/12/21
+ - renamed token to EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE (adding "2D")
+ - renamed extension to ANGLE_surface_d3d_texture_2d_share_handle
+ - added language about supported usage of the shared handle from D3D
+
+ Version 1, 2010/12/07 - first draft.
diff --git a/extensions/EGL_EXT_create_context_robustness.txt b/extensions/EGL_EXT_create_context_robustness.txt
new file mode 100644
index 00000000..a78f8789
--- /dev/null
+++ b/extensions/EGL_EXT_create_context_robustness.txt
@@ -0,0 +1,169 @@
+Name
+
+ EXT_create_context_robustness
+
+Name Strings
+
+ EGL_EXT_create_context_robustness
+
+Contributors
+
+ Daniel Koch, TransGaming
+ Contributors to EGL_KHR_create_context
+
+Contact
+
+ Greg Roth (groth 'at' nvidia.com)
+
+Status
+
+ Complete.
+
+Version
+
+ Version 3, 2011/10/31
+
+Number
+
+ EGL Extension #37
+
+Dependencies
+
+ Requires EGL 1.4
+
+ Written against the EGL 1.4 specification.
+
+ An OpenGL implementation supporting GL_ARB_robustness, an OpenGL ES
+ implementation supporting GL_EXT_robustness, or an implementation
+ supporting equivalent functionality is required.
+
+Overview
+
+ This extension allows creating an OpenGL or OpenGL ES context
+ supporting robust buffer access behavior and a specified graphics
+ reset notification behavior.
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ Accepted as an attribute name in the <*attrib_list> argument to
+ eglCreateContext:
+
+ EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF
+ EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
+
+ Accepted as an attribute value for EGL_CONTEXT_RESET_NOTIFICATION_-
+ STRATEGY_EXT in the <*attrib_list> argument to eglCreateContext:
+
+ EGL_NO_RESET_NOTIFICATION_EXT 0x31BE
+ EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF
+
+Additions to the EGL 1.4 Specification
+
+ Replace section 3.7.1 "Creating Rendering Contexts" from the
+ fifth paragraph through the seventh paragraph:
+
+ <attrib_list> specifies a list of attributes for the context. The
+ list has the same structure as described for eglChooseConfig. If an
+ attribute is not specified in <attrib_list>, then the default value
+ specified below is used instead. <attrib_list> may be NULL or empty
+ (first attribute is EGL_NONE), in which case attributes assume their
+ default values as described below. Most attributes are only meaningful
+ for specific client APIs, and will generate an EGL_BAD_ATTRIBUTE
+ error when specified to create for another client API context.
+
+ Context Versions
+ ----------------
+
+ EGL_CONTEXT_CLIENT_VERSION determines which version of an OpenGL ES
+ context to create. This attribute may only be specified when creating
+ an OpenGL ES context (e.g. when the current rendering API is
+ EGL_OPENGL_ES_API). An attribute value of 1 specifies creation of an
+ OpenGL ES 1.x context. An attribute value of 2 specifies creation of an
+ Open GL ES 2.x context. The default value for EGL_CONTEXT_CLIENT_VERSION
+ is 1.
+
+ Context Robust Access
+ -------------
+
+ EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT indicates whether <robust buffer
+ access> should be enabled for the OpenGL ES context. Robust buffer
+ access is defined in the GL_EXT_robustness extension specification,
+ and the resulting context must support GL_EXT_robustness and robust
+ buffer access as described therein. The default value of
+ EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT is EGL_FALSE.
+
+ Context Reset Notification
+ --------------------------
+
+ The attribute name EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_-
+ EXT specifies the <reset notification behavior> of the rendering
+ context. This attribute is only meaningful for OpenGL ES contexts,
+ and specifying it for other types of contexts will generate an
+ EGL_BAD_ATTRIBUTE error.
+
+ Reset notification behavior is defined in the GL_EXT_robustness
+ extension for OpenGL ES, and the resulting context must support
+ GL_EXT_robustness and the specified reset strategy. The attribute
+ value may be either EGL_NO_RESET_NOTIFICATION_EXT or EGL_LOSE_-
+ CONTEXT_ON_RESET_EXT, which respectively result in disabling
+ delivery of reset notifications or the loss of all context state
+ upon reset notification as described by the GL_EXT_robustness. The
+ default value for EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT
+ is EGL_NO_RESET_NOTIFICATION_EXT.
+
+ Add to the eglCreateContext context creation errors:
+
+ * If <config> does not support a client API context compatible
+ with the requested context flags and context reset notification
+ behavior (for client API types where these attributes are
+ supported), then an EGL_BAD_CONFIG error is generated.
+
+ * If the reset notification behavior of <share_context> and the
+ newly created context are different then an EGL_BAD_MATCH error is
+ generated.
+
+
+Errors
+
+ EGL_BAD_CONFIG is generated if EGL_CONTEXT_OPENGL_ROBUST_ACCESS_-
+ EXT is set to EGL_TRUE and no GL context supporting the GL_EXT_-
+ robustness extension and robust access as described therein can be
+ created.
+
+ EGL_BAD_CONFIG is generated if no GL context supporting the
+ GL_EXT_robustness extension and the specified reset notification
+ behavior (the value of attribute EGL_CONTEXT_RESET_NOTIFICATION_-
+ STRATEGY_EXT) can be created.
+
+ BAD_MATCH is generated if the reset notification behavior of
+ <share_context> does not match the reset notification behavior of
+ the context being created.
+
+New State
+
+ None
+
+Conformance Tests
+
+ TBD
+
+Sample Code
+
+ TBD
+
+Issues
+
+ None
+
+Revision History
+
+ Rev. Date Author Changes
+ ---- ------------ --------- ----------------------------------------
+ 3 31 Oct 2011 groth Reverted to attribute for robust access. Now it's a
+ companion to rather than subset of KHR_create_context
+ 2 11 Oct 2011 groth Merged ANGLE and NV extensions.
+ 1 15 July 2011 groth Initial version
diff --git a/extensions/EXT_draw_buffers.txt b/extensions/EXT_draw_buffers.txt
new file mode 100644
index 00000000..73546021
--- /dev/null
+++ b/extensions/EXT_draw_buffers.txt
@@ -0,0 +1,542 @@
+Name
+
+ EXT_draw_buffers
+
+Name Strings
+
+ GL_EXT_draw_buffers
+
+Contributors
+
+ Contributors to GL_NV_draw_buffers
+ Contributors to GL_NV_fbo_color_attachments
+ Contributors to the OpenGL ES 2.0 specification
+ Contributors to the OpenGLSL ES 1.0.17 specification
+ Contributors to the OpenGL ES 3.0 specification
+ Nicolas Capens, TransGaming Inc.
+ Daniel Koch, TransGaming Inc.
+ Alastair Patrick, Google Inc.
+ Kenneth Russell, Google Inc.
+ Greg Roth, NVIDIA Corporation
+ Ben Bowman, Imagination Technologies
+ Members of the WebGL and OpenGL ES working groups
+
+Contact
+
+ Daniel Koch (daniel 'at' transgaming.com)
+
+Status
+
+ Draft Complete
+
+Version
+
+ Last Modified Date: January 30, 2013
+ Revision: #7
+
+Number
+
+ TBD
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+ The extension is written against the OpenGL ES 2.0 specification.
+
+ ANGLE_framebuffer_blit affects the definition of this extension.
+ APPLE_framebuffer_multisample affects the definitin of this extension.
+
+Overview
+
+ This extension increases the number of available framebuffer object
+ color attachment points, extends OpenGL ES 2.0 to allow multiple output
+ colors, and provides a mechanism for directing those outputs to
+ multiple color buffers.
+
+ This extension is similar to the combination of the GL_NV_draw_buffers
+ and GL_NV_fbo_color_attachments extensions, but imposes certain
+ restrictions informed by the OpenGL ES 3.0 API.
+
+New Procedures and Functions
+
+ void DrawBuffersEXT(sizei n, const enum *bufs);
+
+New Tokens
+
+ Accepted by the <pname> parameter of GetIntegerv:
+
+ MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
+
+ Accepted by the <pname> parameters of GetIntegerv and GetFloatv:
+
+ MAX_DRAW_BUFFERS_EXT 0x8824
+ DRAW_BUFFER0_EXT 0x8825
+ DRAW_BUFFER1_EXT 0x8826
+ DRAW_BUFFER2_EXT 0x8827
+ DRAW_BUFFER3_EXT 0x8828
+ DRAW_BUFFER4_EXT 0x8829
+ DRAW_BUFFER5_EXT 0x882A
+ DRAW_BUFFER6_EXT 0x882B
+ DRAW_BUFFER7_EXT 0x882C
+ DRAW_BUFFER8_EXT 0x882D
+ DRAW_BUFFER9_EXT 0x882E
+ DRAW_BUFFER10_EXT 0x882F
+ DRAW_BUFFER11_EXT 0x8830
+ DRAW_BUFFER12_EXT 0x8831
+ DRAW_BUFFER13_EXT 0x8832
+ DRAW_BUFFER14_EXT 0x8833
+ DRAW_BUFFER15_EXT 0x8834
+
+ Accepted by the <attachment> parameter of FramebufferRenderbuffer,
+ FramebufferTexture2D and GetFramebufferAttachmentParameteriv, and by
+ the <bufs> parameter of DrawBuffersEXT:
+
+ COLOR_ATTACHMENT0_EXT 0x8CE0
+ COLOR_ATTACHMENT1_EXT 0x8CE1
+ COLOR_ATTACHMENT2_EXT 0x8CE2
+ COLOR_ATTACHMENT3_EXT 0x8CE3
+ COLOR_ATTACHMENT4_EXT 0x8CE4
+ COLOR_ATTACHMENT5_EXT 0x8CE5
+ COLOR_ATTACHMENT6_EXT 0x8CE6
+ COLOR_ATTACHMENT7_EXT 0x8CE7
+ COLOR_ATTACHMENT8_EXT 0x8CE8
+ COLOR_ATTACHMENT9_EXT 0x8CE9
+ COLOR_ATTACHMENT10_EXT 0x8CEA
+ COLOR_ATTACHMENT11_EXT 0x8CEB
+ COLOR_ATTACHMENT12_EXT 0x8CEC
+ COLOR_ATTACHMENT13_EXT 0x8CED
+ COLOR_ATTACHMENT14_EXT 0x8CEE
+ COLOR_ATTACHMENT15_EXT 0x8CEF
+
+ The COLOR_ATTACHMENT0_EXT constant is equal to the
+ COLOR_ATTACHMENT0 constant.
+
+ Each COLOR_ATTACHMENT<i>_EXT adheres to COLOR_ATTACHMENT<i>_EXT
+ = COLOR_ATTACHMENT0_EXT + <i>.
+
+Changes to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)
+
+ Section 3.2, (Multisampling). Replace the second paragraph:
+
+ An additional buffer, called the multisample buffer, is added to the
+ window system-provided framebuffer. Pixel sample values, including
+ color, depth, and stencil values, are stored in this buffer. Samples
+ contain separate color values for each fragment color. When the
+ window system-provided framebuffer includes a multisample buffer, it
+ does not include depth or stencil buffers, even if the multisample
+ buffer does not store depth or stencil values. Color buffers do
+ coexist with the multisample buffer, however.
+
+ Section 3.8.2, (Shader Execution) Replace subsection "Shader
+ Outputs":
+
+ The OpenGL ES Shading Language specification describes the values
+ that may be output by a fragment shader. These are gl_FragColor and
+ gl_FragData[n]. The final fragment color values or the final
+ fragment data values written by a fragment shader are clamped to the
+ range [0, 1] and then converted to fixed-point as described in
+ section 2.1.2 for framebuffer color components.
+
+ Writing to gl_FragColor specifies the fragment color (color number
+ zero) that will be used by subsequent stages of the pipeline.
+ Writing to gl_FragData[n] specifies the value of fragment color
+ number n. Any colors, or color components, associated with a
+ fragment that are not written by the fragment shader are undefined.
+ A fragment shader may not statically assign values to both
+ gl_FragColor and gl_FragData. In this case, a compile or link error
+ will result. A shader statically assigns a value to a variable if,
+ after preprocessing, it contains a statement that would write to the
+ variable, whether or not run-time flow of control will cause that
+ statement to be executed.
+
+Changes to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment
+Operations and the Frame Buffer)
+
+ Modify the overview of Chapter 4 and replace the sentences
+ of the fifth paragraph which read:
+
+ "The name of the color buffer of an application-created framebuffer
+ object is COLOR_ATTACHMENT0. The names of the depth and stencil buffers
+ are DEPTH_ATTACHMENT and STENCIL_ATTACHMENT."
+
+ With the following:
+
+ "A framebuffer object has an array of color buffer attachment points,
+ numbered zero through <n>, a depth buffer attachment point, and a
+ stencil buffer attachment point."
+
+ Insert Table 4.3 to Section 4.2.1 (and renumber subsequent tables):
+
+ Symbolic Constant Meaning
+ ----------------- ---------------------
+ NONE No buffer
+
+ COLOR_ATTACHMENT<i>_EXT (see caption) Output fragment color to image
+ attached at color attachment
+ point i
+
+ Table 4.3: Arguments to DrawBuffersEXT when the context is bound to a
+ framebuffer object, and the buffers they indicate. <i> in
+ COLOR_ATTACHMENT<i>_EXT may range from zero to the value of
+ MAX_COLOR_ATTACHMENTS_EXT minus one.
+
+ Replace Section 4.2.1, "Selecting a Buffer for Writing" with the following:
+
+ "By default, color values are written into the front buffer for
+ single buffered surfaces or into the back buffer for back buffered
+ surfaces as determined when making the context current. To control
+ the color buffer into which each of the fragment color values is
+ written, DrawBuffersEXT is used.
+
+ The command
+
+ void DrawBuffersEXT(sizei n, const enum *bufs);
+
+ defines the draw buffers to which all fragment colors are written.
+ <n> specifies the number of buffers in <bufs>. <bufs> is a pointer
+ to an array of symbolic constants specifying the buffer to which
+ each fragment color is written.
+
+ Each buffer listed in <bufs> must be BACK, NONE, or one of the
+ values from table 4.3. Further, acceptable values for the constants
+ in <bufs> depend on whether the GL is using the default framebuffer
+ (i.e., DRAW_FRAMEBUFFER_BINDING is zero), or a framebuffer object
+ (i.e., DRAW_FRAMEBUFFER_BINDING is non-zero). For more information
+ about framebuffer objects, see section 4.4.
+
+ If the GL is bound to the default framebuffer, then <n> must be 1
+ and the constant must be BACK or NONE. When draw buffer zero is
+ BACK, color values are written into the sole buffer for single-
+ buffered contexts, or into the back buffer for double-buffered
+ contexts. If DrawBuffersEXT is supplied with a constant other than
+ BACK and NONE, the error INVALID_OPERATION is generated.
+
+ If the GL is bound to a draw framebuffer object, then each of the
+ constants must be one of the values listed in table 4.3.
+
+ In both cases, the draw buffers being defined correspond in order to
+ the respective fragment colors. The draw buffer for fragment
+ colors beyond <n> is set to NONE.
+
+ The maximum number of draw buffers is implementation-dependent. The
+ number of draw buffers supported can be queried by calling
+ GetIntegerv with the symbolic constant MAX_DRAW_BUFFERS_EXT. An
+ INVALID_VALUE error is generated if <n> is greater than
+ MAX_DRAW_BUFFERS_EXT.
+
+ If the GL is bound to a draw framebuffer object, the <i>th buffer listed
+ in <bufs> must be COLOR_ATTACHMENT<i>_EXT or NONE. Specifying a
+ buffer out of order, BACK, or COLOR_ATTACHMENT<m>_EXT where <m> is
+ greater than or equal to the value of MAX_COLOR_ATTACHMENTS_EXT,
+ will generate the error INVALID_OPERATION.
+
+ If a fragment shader writes to "gl_FragColor", DrawBuffersEXT
+ specifies the set of draw buffers into which the color
+ written to "gl_FragColor" is written. If a fragment shader writes to
+ "gl_FragData", DrawBuffersEXT specifies a set of draw buffers
+ into which each of the multiple output colors defined by these
+ variables are separately written. If a fragment shader writes to
+ neither "gl_FragColor" nor "gl_FragData" the values of the
+ fragment colors following shader execution are undefined, and may
+ differ for each fragment color.
+
+ Indicating a buffer or buffers using DrawBuffersEXT causes
+ subsequent pixel color value writes to affect the indicated
+ buffers. If the GL is bound to a draw framebuffer object and a draw
+ buffer selects an attachment that has no image attached, then that
+ fragment color is not written.
+
+ Specifying NONE as the draw buffer for a fragment color will inhibit
+ that fragment color from being written.
+
+ The state required to handle color buffer selection for each
+ framebuffer is an integer for each supported fragment color. For the
+ default framebuffer, in the initial state the draw buffer for
+ fragment color zero is BACK if there is a default framebuffer
+ associated with the context, otherwise NONE. For framebuffer
+ objects, in the initial state the draw buffer for fragment color
+ zero is COLOR_ATTACHMENT0_EXT.
+
+ For both the default framebuffer and framebuffer objects, the
+ initial state of draw buffers for fragment colors other than zero is
+ NONE.
+
+ The value of the draw buffer selected for fragment color <i> can be
+ queried by calling GetIntegerv with the symbolic constant
+ DRAW_BUFFER<i>_EXT."
+
+ Modify Section 4.2.3 (Clearing the Buffers) and replace the first
+ two paragraphs with the following:
+
+ "The GL provides a means for setting portions of every pixel in a
+ particular buffer to the same value. The argument to
+
+ void Clear(bitfield buf);
+
+ is the bitwise OR of a number of values indicating which buffers are
+ to be cleared. The values are COLOR_BUFFER_BIT, DEPTH_BUFFER_BIT, and
+ STENCIL_BUFFER_BIT, indicating the buffers currently enabled for color
+ writing, the depth buffer, and the stencil buffer (see below),
+ respectively. The value to which each buffer is cleared depends on
+ the setting of the clear value for that buffer. If the mask is not a
+ bitwise OR of the specified values, then the error INVALID_VALUE is
+ generated.
+
+ void ClearColor(clampf r, clampf, g, clampf b, clampf a);
+
+ sets the clear value for fixed-point color buffers. Each of the
+ specified components is clamped to [0, 1] and converted to fixed-point
+ as described in section 2.1.2 for framebuffer color components."
+
+ Replace the second paragraph of Section 4.4.1 (Binding and Managing
+ Framebuffer Objects) with the following:
+
+ "The namespace for framebuffer objects is the unsigned integers, with
+ zero reserved by OpenGL ES to refer to the default framebuffer. A
+ framebuffer object is created by binding an unused name to the
+ target FRAMEBUFFER, DRAW_FRAMEBUFFER, or READ_FRAMEBUFFER. The binding
+ is effected by calling
+
+ void BindFramebuffer(enum target, uint framebuffer);
+
+ with <target> set the desired framebuffer target and <framebuffer> set
+ to the unused name. The resulting framebuffer object is a new state
+ vector. There is a number of color attachment points, plus one each
+ for the depth and stencil attachment points. The number of color attachment
+ points is equal to the value of MAX_COLOR_ATTACHMENTS_EXT."
+
+ Replace the third item in the bulleted list in Section 4.4.1 (Binding
+ and Managing Framebuffer Objects) with the following:
+
+ " * The only color buffer bitplanes are the ones defined by the
+ framebuffer attachments points named COLOR_ATTACHMENT0_EXT through
+ COLOR_ATTACHMENT<n>_EXT."
+
+ Modify Section 4.4.3 (Renderbuffer Objects) in the
+ "Attaching Renderbuffer Images to a Framebuffer" subsection as follows:
+
+ Insert the following table:
+
+ Name of attachment
+ ---------------------------------------
+ COLOR_ATTACHMENT<i>_EXT (see caption)
+ DEPTH_ATTACHMENT
+ STENCIL_ATTACHMENT
+
+ Table 4.x: Framebuffer attachment points. <i> in COLOR_ATTACHMENT<i>_EXT
+ may range from zero to the value of MAX_COLOR_ATTACHMENTS_EXT minus 1.
+
+ Modify the third sentence of the paragraph following the definition of
+ FramebufferRenderbuffer to be as follows:
+
+ "<attachment> should be set to one of the attachment points of the
+ framebuffer listed in Table 4.x."
+
+ Modify Section 4.4.3 (Renderbuffer Objects) in the "Attaching Texture
+ Images to a Framebuffer" subsection as follows:
+
+ Modify the last sentence of the paragraph following the definition of
+ FramebufferTexture2D to be as follows:
+
+ "<attachment> must be one of the attachment points of the framebuffer
+ listed in Table 4.x."
+
+ Modify Section 4.4.5 (Framebuffer Completeness) and replace the 3rd
+ item in the bulleted list in the "Framebuffer Attachment Completeness"
+ subsection with the following:
+
+ " * If <attachment> is COLOR_ATTACHMENT<i>_EXT, then <image> must
+ have a color-renderable internal format."
+
+Changes to Chapter 6 of the OpenGL ES 2.0 Specification (State and
+State Requests)
+
+ In section 6.1.3 (Enumerated Queries) modify the third sentence in
+ the definition of GetFramebufferAttachmentParameteriv to be as follows:
+
+ "<attachment> must be one of the attachment points of the framebuffer
+ listed in Table 4.x."
+
+Changes to Chapter 3 of the OpenGL ES Shading Language 1.0.17 Specification (Basics)
+
+ Add a new section:
+
+ 3.4.1 GL_EXT_draw_buffers Extension
+
+ To use the GL_EXT_draw_buffers extension in a shader it
+ must be enabled using the #extension directive.
+
+ The shading language preprocessor #define
+ GL_EXT_draw_buffers will be defined to 1, if the
+ GL_EXT_draw_buffers extension is supported.
+
+Dependencies on ANGLE_framebuffer_blit and APPLE_framebuffer_multisample:
+
+ If neither ANGLE_framebuffer_blit nor APPLE_framebuffer_multisample are
+ supported, then all references to "draw framebuffers" should be replaced
+ with references to "framebuffers". References to DRAW_FRAMEBUFFER_BINDING
+ should be replaced with references to FRAMEBUFFER_BINDING. References to
+ DRAW_FRAMEBUFFER and READ_FRAMEBUFFER should be removed.
+
+ If ANGLE_framebuffer_blit is supported, DRAW_FRAMEBUFFER_BINDING, DRAW_FRAMEBUFFER
+ and READ_FRAMEBUFFER all refer to corresponding _ANGLE suffixed names
+ (they have the same token values).
+
+ If APPLE_framebuffer_multisample is supported, DRAW_FRAMEBUFFER_BINDING,
+ DRAW_FRAMEBUFFER and READ_FRAMEBUFFER all refer to the corresponding _APPLE
+ suffixed names (they have the same token values).
+
+Errors
+
+ The INVALID_OPERATION error is generated if DrawBuffersEXT is called
+ when the default framebuffer is bound and any of the following conditions
+ hold:
+ - <n> is greater than 1 and less than MAX_DRAW_BUFFERS_EXT,
+ - <bufs> contains a value other than BACK or NONE.
+
+ The INVALID_OPERATION error is generated if DrawBuffersEXT is called
+ when bound to a draw framebuffer object and any of the following
+ conditions hold:
+ - the <i>th value in <bufs> is not COLOR_ATTACHMENT<i>_EXT or NONE.
+
+ The INVALID_VALUE error is generated if DrawBuffersEXT is called
+ with a value of <n> which is greater than MAX_DRAW_BUFFERS_EXT.
+
+ The INVALID_ENUM error is generated by FramebufferRenderbuffer if
+ the <attachment> parameter is not one of the values listed in Table 4.x.
+
+ The INVALID_ENUM error is generated by FramebufferTexture2D if
+ the <attachment> parameter is not one of the values listed in Table 4.x.
+
+ The INVALID_ENUM error is generated by GetFramebufferAttachmentParameteriv
+ if the <attachment> parameter is not one of the values listed in Table 4.x.
+
+New State
+
+ Add Table 6.X Framebuffer (State per framebuffer object):
+
+ State Type Get Command Initial Value Description
+ ------------------ ---- ------------ ------------- -----------
+ DRAW_BUFFER<i>_EXT Z10* GetIntegerv see 4.2.1 Draw buffer selected
+ for fragment color i
+
+ Add to Table 6.18 (Implementation Dependent Values)
+
+ Get value Type Get Cmnd Minimum Value Description Sec.
+ -------------------- ---- ----------- ------------- ----------- -----
+ MAX_DRAW_BUFFERS_EXT Z+ GetIntegerv 1 Maximum number of 4.2.1
+ active draw buffers
+ MAX_COLOR_ATTACHMENTS_EXT Z+ GetIntegerv 1 Number of framebuffer 4.4.1
+ color attachment points
+Issues
+
+ See ARB_draw_buffers for relevant issues.
+
+ 1) What are the differences between this extension and NV_draw_buffers
+ + NV_fbo_color_attachments?
+
+ RESOLVED. This extension:
+ - adds interactions with blit_framebuffer and the separate
+ draw/read binding points
+ - The draw buffer and color attachment limits are global instead
+ of per-fbo (see Issue 2)
+ - can be used to with default framebuffer to set NONE/BACK (see Issue 4)
+ - retains the ordering restrictions on color attachments that are
+ imposed by ES 3.0.
+
+ 2) Should the MAX_DRAW_BUFFERS_EXT and MAX_COLOR_ATTACHMENTS_EXT limits
+ be per-framebuffer values or implementation dependent constants?
+
+ DISCUSSION: In ARB_draw_buffers this was per-context (see Issue 2).
+ EXT_framebuffer_object (and subsequently ARB_framebuffer_object, and GL 3.0
+ through GL 4.2) made these queries framebuffer-dependent.
+ However in GL 4.3 and GLES 3.0, these limits were changed from
+ framebuffer-dependent state to implementation-dependent state after
+ much discussion (Bug 7990).
+
+ NV_draw_buffers has MAX_DRAW_BUFFERS listed as per-framebuffer state,
+ but NV_fbo_color_attachments has MAX_COLOR_ATTACHMENTS as an
+ implementation-dependent constant.
+
+ This is relevant because some implementations are not able to support
+ multisampling in conjuction with multiple color attachments. If the
+ query is per-framebuffer, they can report a maximum of one attachment
+ when there are multisampled attachments, but a higher limit when only
+ single-sampled attachments are present.
+
+ RESOLVED. Make this global context state as this is most consistent
+ with GLES 3.0 and updated GL drivers. In an implementation cannot
+ support multisampling in conjunction with multiple color attachments,
+ perhaps such an implementation could report FBO incomplete in this
+ situation, but this is less than desirable.
+
+ 3) Should we support broadcast from gl_FragColor to all gl_FragData[x]
+ or should it be synonymous with gl_FragData[0]?
+
+ DISCUSSION: With NV_draw_buffers, writing to gl_FragColor writes to all
+ the enabled draw buffers (ie broadcast). In OpenGL ES 3.0 when using
+ ESSL 1.0, gl_FragColor is equivalent to writing a single output to
+ gl_FragData[0] and multiple outputs are not possible. When using ESSL 3.0,
+ only user-defined out variables may be used.
+
+ If broadcast is supported, some implementations may have to replace
+ writes to gl_FragColor with replicated writes to all possible gl_FragData
+ locations when this extension is enabled.
+
+ RESOLVED: Writes to gl_FragColor are broadcast to all enabled color
+ buffers. ES 3.0 using ESSL 1.0 doesn't support broadcast because
+ ESSL 1.0 was not extended to have multiple color outputs (but that is
+ what this extension adds). ESSL 3.0 doesn't support the broadcast because
+ it doesn't have the gl_FragColor variable at all, and only has user-
+ defined out variables. This extension extends ESSL 1.0 to have multiple
+ color outputs. Broadcasting from gl_FragColor to all enabled color
+ buffers is the most consistent with existing draw buffer extensions to
+ date (both NV_draw_buffers and desktop GL).
+
+ 4) Should we allow DrawBuffersEXT to be called when the default FBO is
+ bound?
+
+ DISCUSSION: NV_draw_buffers specifies that DrawBuffersNV errors with
+ INVALID_OPERATION when the default FBO is bound. OpenGL ES 3.0 allows
+ DrawBuffers to toggle between BACK and NONE on the default FBO.
+
+ An implementation that does not natively support disabling the drawbuffer
+ on the default FBO could emulate this by disabling color writes.
+
+ RESOLVED: Allow DrawBuffersEXT to be called for the default FBO. This
+ is more forward looking and is compatible with ES 3.0.
+
+ 5) What are the requirements on the color attachment sizes and formats?
+
+ RESOLVED: ES 2.0 requires that all color buffers attached to application-
+ created framebuffer objects must have the same number of bitplanes
+ (Chapter 4 overview p91). ES 2.0 also requires that all attached images
+ have the same width and height (Section 4.4.5 Framebuffer Completeness).
+ This extension does not lift those requirements, and failing to meet
+ them will result in an incomplete FBO.
+
+ 6) Does this have any interactions with glClear?
+
+ RESOLVED: Yes. When multiple color buffers are enabled for writing,
+ glClear clears all of the color buffers. Added language clarifying
+ that glClear and glClearColor may affect multiple color buffers.
+
+Revision History
+
+ 01/30/2013 dgkoch add issue 6 and clear interactions
+ renamed to EXT_draw_buffers based on feedback
+ changed resolution of issue 3.
+ 01/23/2013 dgkoch add resolutions to issues 2-4.
+ add issue 5.
+ Add Table 4.x and update various explicit
+ references to COLOR_ATTACHMENT0.
+ Add errors.
+ 11/13/2012 dgkoch add revision history
+ add text from updated ES 3.0 spec
+ add issues for discussion
+ 10/16/2012 kbr update name string
+ 10/16/2012 kbr remove restrition requiring draw buffer 0 to be non-NULL
+ 10/12/2012 kbr remove references to GetDoublev and ReadBuffer
+ 10/11/2012 kbr initial draft extension
+
diff --git a/extensions/EXT_robustness.txt b/extensions/EXT_robustness.txt
new file mode 100644
index 00000000..1c26a558
--- /dev/null
+++ b/extensions/EXT_robustness.txt
@@ -0,0 +1,365 @@
+Name
+
+ EXT_robustness
+
+Name Strings
+
+ GL_EXT_robustness
+
+Contributors
+
+ Daniel Koch, TransGaming
+ Nicolas Capens, TransGaming
+ Contributors to ARB_robustness
+
+Contact
+
+ Greg Roth, NVIDIA (groth 'at' nvidia.com)
+
+Status
+
+ Complete.
+
+Version
+
+ Version 3, 2011/10/31
+
+Number
+
+ OpenGL ES Extension #107
+
+Dependencies
+
+ This extension is written against the OpenGL ES 2.0 Specification
+ but can apply to OpenGL ES 1.1 and up.
+
+ EGL_EXT_create_context_robustness is used to determine if a context
+ implementing this extension supports robust buffer access, and if it
+ supports reset notification.
+
+Overview
+
+ Several recent trends in how OpenGL integrates into modern computer
+ systems have created new requirements for robustness and security
+ for OpenGL rendering contexts.
+
+ Additionally GPU architectures now support hardware fault detection;
+ for example, video memory supporting ECC (error correcting codes)
+ and error detection. OpenGL contexts should be capable of recovering
+ from hardware faults such as uncorrectable memory errors. Along with
+ recovery from such hardware faults, the recovery mechanism can
+ also allow recovery from video memory access exceptions and system
+ software failures. System software failures can be due to device
+ changes or driver failures.
+
+ OpenGL queries that that return (write) some number of bytes to a
+ buffer indicated by a pointer parameter introduce risk of buffer
+ overflows that might be exploitable by malware. To address this,
+ queries with return value sizes that are not expressed directly by
+ the parameters to the query itself are given additional API
+ functions with an additional parameter that specifies the number of
+ bytes in the buffer and never writing bytes beyond that limit. This
+ is particularly useful for multi-threaded usage of OpenGL contexts
+ in a "share group" where one context can change objects in ways that
+ can cause buffer overflows for another context's OpenGL queries.
+
+ The original ARB_vertex_buffer_object extension includes an issue
+ that explicitly states program termination is allowed when
+ out-of-bounds vertex buffer object fetches occur. Modern graphics
+ hardware is capable well-defined behavior in the case of out-of-
+ bounds vertex buffer object fetches. Older hardware may require
+ extra checks to enforce well-defined (and termination free)
+ behavior, but this expense is warranted when processing potentially
+ untrusted content.
+
+ The intent of this extension is to address some specific robustness
+ goals:
+
+ * For all existing OpenGL queries, provide additional "safe" APIs
+ that limit data written to user pointers to a buffer size in
+ bytes that is an explicit additional parameter of the query.
+
+ * Provide a mechanism for an OpenGL application to learn about
+ graphics resets that affect the context. When a graphics reset
+ occurs, the OpenGL context becomes unusable and the application
+ must create a new context to continue operation. Detecting a
+ graphics reset happens through an inexpensive query.
+
+ * Provide an enable to guarantee that out-of-bounds buffer object
+ accesses by the GPU will have deterministic behavior and preclude
+ application instability or termination due to an incorrect buffer
+ access. Such accesses include vertex buffer fetches of
+ attributes and indices, and indexed reads of uniforms or
+ parameters from buffers.
+
+New Procedures and Functions
+
+ enum GetGraphicsResetStatusEXT();
+
+ void ReadnPixelsEXT(int x, int y, sizei width, sizei height,
+ enum format, enum type, sizei bufSize,
+ void *data);
+
+ void GetnUniformfvEXT(uint program, int location, sizei bufSize,
+ float *params);
+ void GetnUniformivEXT(uint program, int location, sizei bufSize,
+ int *params);
+
+New Tokens
+
+ Returned by GetGraphicsResetStatusEXT:
+
+ NO_ERROR 0x0000
+ GUILTY_CONTEXT_RESET_EXT 0x8253
+ INNOCENT_CONTEXT_RESET_EXT 0x8254
+ UNKNOWN_CONTEXT_RESET_EXT 0x8255
+
+ Accepted by the <value> parameter of GetBooleanv, GetIntegerv,
+ and GetFloatv:
+
+ CONTEXT_ROBUST_ACCESS_EXT 0x90F3
+ RESET_NOTIFICATION_STRATEGY_EXT 0x8256
+
+ Returned by GetIntegerv and related simple queries when <value> is
+ RESET_NOTIFICATION_STRATEGY_EXT :
+
+ LOSE_CONTEXT_ON_RESET_EXT 0x8252
+ NO_RESET_NOTIFICATION_EXT 0x8261
+
+Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation)
+
+Add a new subsection after 2.5 "GL Errors" and renumber subsequent
+sections accordingly.
+
+ 2.6 "Graphics Reset Recovery"
+
+ Certain events can result in a reset of the GL context. Such a reset
+ causes all context state to be lost. Recovery from such events
+ requires recreation of all objects in the affected context. The
+ current status of the graphics reset state is returned by
+
+ enum GetGraphicsResetStatusEXT();
+
+ The symbolic constant returned indicates if the GL context has been
+ in a reset state at any point since the last call to
+ GetGraphicsResetStatusEXT. NO_ERROR indicates that the GL context
+ has not been in a reset state since the last call.
+ GUILTY_CONTEXT_RESET_EXT indicates that a reset has been detected
+ that is attributable to the current GL context.
+ INNOCENT_CONTEXT_RESET_EXT indicates a reset has been detected that
+ is not attributable to the current GL context.
+ UNKNOWN_CONTEXT_RESET_EXT indicates a detected graphics reset whose
+ cause is unknown.
+
+ If a reset status other than NO_ERROR is returned and subsequent
+ calls return NO_ERROR, the context reset was encountered and
+ completed. If a reset status is repeatedly returned, the context may
+ be in the process of resetting.
+
+ Reset notification behavior is determined at context creation time,
+ and may be queried by calling GetIntegerv with the symbolic constant
+ RESET_NOTIFICATION_STRATEGY_EXT.
+
+ 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[fn1].
+ [fn1: In this case it is recommended that implementations should
+ not allow loss of context state no matter what events occur.
+ However, this is only a recommendation, and cannot be relied
+ upon by applications.]
+
+ If the behavior is LOSE_CONTEXT_ON_RESET_EXT, a graphics reset will
+ result in the loss of all context state, requiring the recreation of
+ all associated objects. In this case GetGraphicsResetStatusEXT may
+ return any of the values described above.
+
+ If a graphics reset notification occurs in a context, a notification
+ must also occur in all other contexts which share objects with that
+ context[fn2].
+ [fn2: The values returned by GetGraphicsResetStatusEXT in the
+ different contexts may differ.]
+
+ Add to Section 2.8 "Vertex Arrays" before subsection "Transferring
+ Array Elements"
+
+ Robust buffer access is enabled by creating a context with robust
+ access enabled through the window system binding APIs. When enabled,
+ indices within the vertex array that lie outside the arrays defined
+ for enabled attributes result in undefined values for the
+ corresponding attributes, but cannot result in application failure.
+ Robust buffer access behavior may be queried by calling GetIntegerv
+ with the symbolic constant CONTEXT_ROBUST_ACCESS_EXT.
+
+Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment
+Operations and the Frame Buffer)
+
+ Modify section 4.3.1 "Reading Pixels"
+
+ Pixels are read using
+
+ void ReadPixels(int x, int y, sizei width, sizei height,
+ enum format, enum type, void *data);
+ void ReadnPixelsEXT(int x, int y, sizei width, sizei height,
+ enum format, enum type, sizei bufSize,
+ void *data);
+
+ Add to the description of ReadPixels:
+
+ ReadnPixelsEXT behaves identically to ReadPixels except that it does
+ not write more than <bufSize> bytes into <data>. If the buffer size
+ required to fill all the requested data is greater than <bufSize> an
+ INVALID_OPERATION error is generated and <data> is not altered.
+
+Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special
+Functions):
+
+ None
+
+Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and
+State Requests)
+
+ Modify Section 6.1.8 "Shader and Program Queries"
+
+ The commands
+
+ void GetUniformfv(uint program, int location, float *params);
+ void GetnUniformfvEXT(uint program, int location, sizei bufSize,
+ float *params);
+ void GetUniformiv(uint program, int location, int *params);
+ void GetnUniformivEXT(uint program, int location, sizei bufSize,
+ int *params);
+
+ return the value or values of the uniform at location <location>
+ for program object <program> in the array <params>. Calling
+ GetnUniformfvEXT or GetnUniformivEXT ensures that no more than
+ <bufSize> bytes are written into <params>. If the buffer size
+ required to fill all the requested data is greater than <bufSize> an
+ INVALID_OPERATION error is generated and <params> is not altered.
+ ...
+
+Additions to The OpenGL ES Shading Language Specification, Version 1.
+
+ Append to the third paragraph of section 4.1.9 "Arrays"
+
+ If robust buffer access is enabled via the OpenGL ES API, such
+ indexing must not result in abnormal program termination. The
+ results are still undefined, but implementations are encouraged to
+ produce zero values for such accesses.
+
+Interactions with EGL_EXT_create_context_robustness
+
+ If the EGL window-system binding API is used to create a context,
+ the EGL_EXT_create_context_robustness extension is supported, and
+ the attribute EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT is set to
+ EGL_TRUE when eglCreateContext is called, the resulting context will
+ perform robust buffer access as described above in section 2.8, and
+ the CONTEXT_ROBUST_ACCESS_EXT query will return GL_TRUE as described
+ above in section 6.1.5.
+
+ If the EGL window-system binding API is used to create a context and
+ the EGL_EXT_create_context_robustness extension is supported, then
+ the value of attribute EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT
+ determines the reset notification behavior and the value of
+ RESET_NOTIFICATION_STRATEGY_EXT, as described in section 2.6.
+
+Errors
+
+ ReadnPixelsEXT, GetnUniformfvEXT, and GetnUniformivEXT share all the
+ errors of their unsized buffer query counterparts with the addition
+ that INVALID_OPERATION is generated if the buffer size required to
+ fill all the requested data is greater than <bufSize>.
+
+New Implementation Dependent State
+
+ Get Value Type Get Command Minimum Value Description Sec. Attribute
+ --------- ---- ----------- ------------- --------------------------- ----- ---------
+ CONTEXT_ROBUST_ACCESS_EXT B GetIntegerv - Robust access enabled 6.1.5 -
+ RESET_NOTIFICATION_STRATEGY_EXT Z_2 GetIntegerv See sec. 2.6 Reset notification behavior 2.6 -
+
+Issues
+
+
+ 1. What should this extension be called?
+
+ RESOLVED: EXT_robustness
+
+ Since this is intended to be a version of ARB_robustness for
+ OpenGL ES, it should be named accordingly.
+
+ 2. How does this extension differ from Desktop GL's ARB_robustness?
+
+ RESOLVED: Because EGL_EXT_create_context_robustness uses a
+ separate attribute to enable robust buffer access, a
+ corresponding query is added here.
+
+ 3. Should we provide a context creation mechanism to enable this extension?
+
+ RESOLVED. Yes.
+
+ Currently, EGL_EXT_create_context_robustness provides this
+ mechanism via two unique attributes. These attributes differ
+ from those specified by KHR_create_context to allow for
+ differences in what functionality those attributes define.
+
+ 4. What can cause a graphics reset?
+
+ Either user or implementor errors may result in a graphics reset.
+ If the application attempts to perform a rendering that takes too long
+ whether due to an infinite loop in a shader or even just a rendering
+ operation that takes too long on the given hardware. Implementation
+ errors may produce badly formed hardware commands. Memory access errors
+ may result from user or implementor mistakes. On some systems, power
+ management events such as system sleep, screen saver activation, or
+ pre-emption may also context resets to occur. Any of these events may
+ result in a graphics reset event that will be detectable by the
+ mechanism described in this extension.
+
+ 5. How should the application react to a reset context event?
+
+ RESOLVED: For this extension, the application is expected to query
+ the reset status until NO_ERROR is returned. If a reset is encountered,
+ at least one *RESET* status will be returned. Once NO_ERROR is again
+ encountered, the application can safely destroy the old context and
+ create a new one.
+
+ After a reset event, apps should not use a context for any purpose
+ other than determining its reset status, and then destroying it. If a
+ context receives a reset event, all other contexts in its share group
+ will also receive reset events, and should be destroyed and
+ recreated.
+
+ Apps should be cautious in interpreting the GUILTY and INNOCENT reset
+ statuses. These are guidelines to the immediate cause of a reset, but
+ not guarantees of the ultimate cause.
+
+ 6. If a graphics reset occurs in a shared context, what happens in
+ shared contexts?
+
+ RESOLVED: A reset in one context will result in a reset in all other
+ contexts in its share group.
+
+ 7. How can an application query for robust buffer access support,
+ since this is now determined at context creation time?
+
+ RESOLVED. The application can query the value of ROBUST_ACCESS_EXT
+ using GetIntegerv. If true, this functionality is enabled.
+
+ 8. How is the reset notification behavior controlled?
+
+ RESOLVED: Reset notification behavior is determined at context
+ creation time using EGL/GLX/WGL/etc. mechanisms. In order that shared
+ objects be handled predictably, a context cannot share with
+ another context unless both have the same reset notification
+ behavior.
+
+
+Revision History
+
+ Rev. Date Author Changes
+ ---- ------------ --------- ----------------------------------------
+ 3 31 Oct 2011 groth Reverted to attribute for robust access. Now it's a
+ companion to rather than subset of KHR_create_context
+ 2 11 Oct 2011 groth Merged ANGLE and NV extensions.
+ Convert to using flag to indicate robust access.
+ 1 15 July 2011 groth Initial version
diff --git a/extensions/EXT_texture_storage.txt b/extensions/EXT_texture_storage.txt
new file mode 100644
index 00000000..fd629e7b
--- /dev/null
+++ b/extensions/EXT_texture_storage.txt
@@ -0,0 +1,1090 @@
+Name
+
+ EXT_texture_storage
+
+Name Strings
+
+ GL_EXT_texture_storage
+
+Contact
+
+ Bruce Merry (bmerry 'at' gmail.com)
+ Ian Romanick, Intel (ian.d.romanick 'at' intel.com)
+
+Contributors
+
+ Jeremy Sandmel, Apple
+ Bruce Merry, ARM
+ Tom Olson, ARM
+ Benji Bowman, Imagination Technologies
+ Ian Romanick, Intel
+ Jeff Bolz, NVIDIA
+ Pat Brown, NVIDIA
+ Maurice Ribble, Qualcomm
+ Lingjun Chen, Qualcomm
+ Daniel Koch, Transgaming Inc
+
+Status
+
+ Complete.
+
+Version
+
+ Last Modified Date: November 11, 2011
+ Author Revision: 24
+
+Number
+
+ OpenGL ES Extension #108
+
+Dependencies
+
+ OpenGL ES 1.0, OpenGL ES 2.0 or OpenGL 1.2 is required.
+
+ OES_texture_npot, OES_texture_cube_map, OES_texture_3D,
+ OES_depth_texture, OES_packed_depth_stencil,
+ OES_compressed_paletted_texture, OES_texture_float, OES_texture_half_float
+ EXT_texture_type_2_10_10_10_REV, EXT_texture_format_BGRA8888,
+ EXT_texture3D, OES_texture_npot, APPLE_texture_2D_limited_npot,
+ ARB_texture_cube_map, ARB_texture_cube_map_array,
+ ARB_texture_rectangle, SGIS_generate_mipmap,
+ EXT_direct_state_access, OES_EGL_image, WGL_ARB_render_texture,
+ GLX_EXT_texture_from_pixmap, and core specifications that
+ incorporate these extensions affect the definition of this
+ extension.
+
+ This extension is written against the OpenGL 3.2 Core Profile
+ specification.
+
+Overview
+
+ The texture image specification commands in OpenGL allow each level
+ to be separately specified with different sizes, formats, types and
+ so on, and only imposes consistency checks at draw time. This adds
+ overhead for implementations.
+
+ This extension provides a mechanism for specifying the entire
+ structure of a texture in a single call, allowing certain
+ consistency checks and memory allocations to be done up front. Once
+ specified, the format and dimensions of the image array become
+ immutable, to simplify completeness checks in the implementation.
+
+ When using this extension, it is no longer possible to supply texture
+ data using TexImage*. Instead, data can be uploaded using TexSubImage*,
+ or produced by other means (such as render-to-texture, mipmap generation,
+ or rendering to a sibling EGLImage).
+
+ This extension has complicated interactions with other extensions.
+ The goal of most of these interactions is to ensure that a texture
+ is always mipmap complete (and cube complete for cubemap textures).
+
+IP Status
+
+ No known IP claims
+
+New Procedures and Functions
+
+ void TexStorage1DEXT(enum target, sizei levels,
+ enum internalformat,
+ sizei width);
+
+ void TexStorage2DEXT(enum target, sizei levels,
+ enum internalformat,
+ sizei width, sizei height);
+
+ void TexStorage3DEXT(enum target, sizei levels,
+ enum internalformat,
+ sizei width, sizei height, sizei depth);
+
+ void TextureStorage1DEXT(uint texture, enum target, sizei levels,
+ enum internalformat,
+ sizei width);
+
+ void TextureStorage2DEXT(uint texture, enum target, sizei levels,
+ enum internalformat,
+ sizei width, sizei height);
+
+ void TextureStorage3DEXT(uint texture, enum target, sizei levels,
+ enum internalformat,
+ sizei width, sizei height, sizei depth);
+
+New Types
+
+ None
+
+New Tokens
+
+ Accepted by the <value> parameter of GetTexParameter{if}v:
+
+ TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
+
+ Accepted by the <internalformat> parameter of TexStorage* when
+ implemented on OpenGL ES:
+
+ ALPHA8_EXT 0x803C /* reuse tokens from EXT_texture */
+ LUMINANCE8_EXT 0x8040
+ LUMINANCE8_ALPHA8_EXT 0x8045
+
+ (if OES_texture_float is supported)
+ RGBA32F_EXT 0x8814 /* reuse tokens from ARB_texture_float */
+ RGB32F_EXT 0x8815
+ ALPHA32F_EXT 0x8816
+ LUMINANCE32F_EXT 0x8818
+ LUMINANCE_ALPHA32F_EXT 0x8819
+
+ (if OES_texture_half_float is supported)
+ RGBA16F_EXT 0x881A /* reuse tokens from ARB_texture_float */
+ RGB16F_EXT 0x881B
+ ALPHA16F_EXT 0x881C
+ LUMINANCE16F_EXT 0x881E
+ LUMINANCE_ALPHA16F_EXT 0x881F
+
+ (if EXT_texture_type_2_10_10_10_REV is supported)
+ RGB10_A2_EXT 0x8059 /* reuse tokens from EXT_texture */
+ RGB10_EXT 0x8052
+
+ (if EXT_texture_format_BGRA8888 is supported)
+ BGRA8_EXT 0x93A1
+
+
+Additions to Chapter 2 of the OpenGL 3.2 Core Profile Specification
+(OpenGL Operation)
+
+ None
+
+Additions to Chapter 3 of the OpenGL 3.2 Core Profile Specification
+(Rasterization)
+
+ After section 3.8.1 (Texture Image Specification) add a new
+ subsection called "Immutable-format texture images":
+
+ "An alterative set of commands is provided for specifying the
+ properties of all levels of a texture at once. Once a texture is
+ specified with such a command, the format and dimensions of all
+ levels becomes immutable, unless it is a proxy texture (since
+ otherwise it would no longer be possible to use the proxy). The
+ contents of the images and the parameters can still be modified.
+ Such a texture is referred to as an "immutable-format" texture. The
+ immutability status of a texture can be determined by calling
+ GetTexParameter with <pname> TEXTURE_IMMUTABLE_FORMAT_EXT.
+
+ Each of the commands below is described by pseudo-code which
+ indicates the effect on the dimensions and format of the texture.
+ For all of the commands, the following apply in addition to the
+ pseudo-code:
+
+ - If the default texture object is bound to <target>, an
+ INVALID_OPERATION error is generated.
+ - If executing the pseudo-code would lead to an error, the error is
+ generated and the command will have no effect.
+ - Any existing levels that are not replaced are reset to their
+ initial state.
+ - If <width>, <height>, <depth> or <levels> is less than 1, the
+ error INVALID_VALUE is generated.
+ - Since no pixel data are provided, the <format> and <type> values
+ used in the pseudo-code are irrelevant; they can be considered to
+ be any values that are legal to use with <internalformat>.
+ - If the command is successful, TEXTURE_IMMUTABLE_FORMAT_EXT becomes
+ TRUE.
+ - If <internalformat> is a specific compressed texture format, then
+ references to TexImage* should be replaced by CompressedTexImage*,
+ with <format>, <type> and <data> replaced by any valid <imageSize> and
+ <data>. If there is no <imageSize> for which this command would have
+ been valid, an INVALID_OPERATION error is generated [fn: This
+ condition is not required for OpenGL, but is necessary for OpenGL
+ ES which does not support on-the-fly compression.]
+ - If <internalformat> is one of the internal formats listed in table
+ 3.11, an INVALID_ENUM error is generated. [fn: The corresponding table
+ in OpenGL ES 2.0 is table 3.8.]
+
+ The command
+
+ void TexStorage1DEXT(enum target, sizei levels,
+ enum internalformat,
+ sizei width);
+
+ specifies all the levels of a one-dimensional texture (or proxy) at
+ the same time. It is described by the pseudo-code below:
+
+ for (i = 0; i < levels; i++)
+ {
+ TexImage1D(target, i, internalformat, width, 0,
+ format, type, NULL);
+ width = max(1, floor(width / 2));
+ }
+
+ If <target> is not TEXTURE_1D or PROXY_TEXTURE_1D then INVALID_ENUM
+ is generated. If <levels> is greater than floor(log_2(width)) + 1
+ then INVALID_OPERATION is generated.
+
+ The command
+
+ void TexStorage2DEXT(enum target, sizei levels,
+ enum internalformat,
+ sizei width, sizei height);
+
+ specifies all the levels of a two-dimensional, cube-map,
+ one-dimension array or rectangle texture (or proxy) at the same
+ time. The pseudo-code depends on the <target>:
+
+ [PROXY_]TEXTURE_2D, [PROXY_]TEXTURE_RECTANGLE or
+ PROXY_TEXTURE_CUBE_MAP:
+
+ for (i = 0; i < levels; i++)
+ {
+ TexImage2D(target, i, internalformat, width, height, 0,
+ format, type, NULL);
+ width = max(1, floor(width / 2));
+ height = max(1, floor(height / 2));
+ }
+
+ TEXTURE_CUBE_MAP:
+
+ for (i = 0; i < levels; i++)
+ {
+ for face in (+X, -X, +Y, -Y, +Z, -Z)
+ {
+ TexImage2D(face, i, internalformat, width, height, 0,
+ format, type, NULL);
+ }
+ width = max(1, floor(width / 2));
+ height = max(1, floor(height / 2));
+ }
+
+ [PROXY_]TEXTURE_1D_ARRAY:
+
+ for (i = 0; i < levels; i++)
+ {
+ TexImage2D(target, i, internalformat, width, height, 0,
+ format, type, NULL);
+ width = max(1, floor(width / 2));
+ }
+
+ If <target> is not one of those listed above, the error INVALID_ENUM
+ is generated.
+
+ The error INVALID_OPERATION is generated if any of the following
+ conditions hold:
+ - <target> is [PROXY_]TEXTURE_1D_ARRAY and <levels> is greater than
+ floor(log_2(width)) + 1
+ - <target> is not [PROXY_]TEXTURE_1D_ARRAY and <levels> is greater
+ than floor(log_2(max(width, height))) + 1
+
+ The command
+
+ void TexStorage3DEXT(enum target, sizei levels, enum internalformat,
+ sizei width, sizei height, sizei depth);
+
+ specifies all the levels of a three-dimensional, two-dimensional
+ array texture, or cube-map array texture (or proxy). The pseudo-code
+ depends on <target>:
+
+ [PROXY_]TEXTURE_3D:
+
+ for (i = 0; i < levels; i++)
+ {
+ TexImage3D(target, i, internalformat, width, height, depth, 0,
+ format, type, NULL);
+ width = max(1, floor(width / 2));
+ height = max(1, floor(height / 2));
+ depth = max(1, floor(depth / 2));
+ }
+
+ [PROXY_]TEXTURE_2D_ARRAY, [PROXY_]TEXTURE_CUBE_MAP_ARRAY_ARB:
+
+ for (i = 0; i < levels; i++)
+ {
+ TexImage3D(target, i, internalformat, width, height, depth, 0,
+ format, type, NULL);
+ width = max(1, floor(width / 2));
+ height = max(1, floor(height / 2));
+ }
+
+ If <target> is not one of those listed above, the error INVALID_ENUM
+ is generated.
+
+ The error INVALID_OPERATION is generated if any of the following
+ conditions hold:
+ - <target> is [PROXY_]TEXTURE_3D and <levels> is greater than
+ floor(log_2(max(width, height, depth))) + 1
+ - <target> is [PROXY_]TEXTURE_2D_ARRAY or
+ [PROXY_]TEXTURE_CUBE_MAP_ARRAY_EXT and <levels> is greater than
+ floor(log_2(max(width, height))) + 1
+
+ After a successful call to any TexStorage* command with a non-proxy
+ target, the value of TEXTURE_IMMUTABLE_FORMAT_EXT for this texture
+ object is set to TRUE, and no further changes to the dimensions or
+ format of the texture object may be made. Other commands may only
+ alter the texel values and texture parameters. Using any of the
+ following commands with the same texture will result in the error
+ INVALID_OPERATION being generated, even if it does not affect the
+ dimensions or format:
+
+ - TexImage*
+ - CompressedTexImage*
+ - CopyTexImage*
+ - TexStorage*
+
+ The TextureStorage* commands operate identically to the
+ corresponding command where "Texture" is substituted for "Tex"
+ except, rather than updating the current bound texture for the
+ texture unit indicated by the current active texture state and the
+ target parameter, these "Texture" commands update the texture object
+ named by the initial texture parameter. The error INVALID_VALUE
+ is generated if <texture> is zero.
+ "
+
+ In section 3.8.6 (Texture Parameters), after the sentence
+
+ "In the remainder of section 3.8, denote by lod_min, lod_max,
+ level_base, and level_max the values of the texture parameters
+ TEXTURE_MIN_LOD, TEXTURE_MAX_LOD, TEXTURE_BASE_LEVEL, and
+ TEXTURE_MAX_LEVEL respectively."
+
+ add
+
+ "However, if TEXTURE_IMMUTABLE_FORMAT_EXT is
+ TRUE, then level_base is clamped to the range [0, <levels> - 1] and
+ level_max is then clamped to the range [level_base, <levels> - 1],
+ where <levels> is the parameter passed the call to TexStorage* for
+ the texture object.
+
+ In section 3.8.9 (Rendering feedback loops) replace all references
+ to TEXTURE_BASE_LEVEL by level_base.
+
+ In section 3.8.9 (Mipmapping), replace the paragraph starting "Each
+ array in a mipmap is defined..." by
+
+ "Each array in a mipmap is defined using TexImage3D, TexImage2D,
+ CopyTexImage2D, TexImage1D, CopyTexImage1D, or by functions that are
+ defined in terms of these functions. Level-of-detail numbers proceed
+ from level_base for the original texel array through the maximum
+ level p, with each unit increase indicating an array of half the
+ dimensions of the previous one (rounded down to the next integer if
+ fractional) as already described. For immutable-format textures,
+ p is one less than the <levels> parameter passed to TexStorage*;
+ otherwise p = floor(log_2(maxsize)) + level_base. All arrays from
+ level_base through q = min(p, level_max) must be defined, as
+ discussed in section 3.8.12."
+
+ In section 3.8.12 (Texture Completeness), modify the last sentence
+ to avoid refering to level_base and level_max:
+
+ "An implementation may allow a texture image array of level 1 or
+ greater to be created only if a mipmap complete set of image arrays
+ consistent with the requested array can be supported where the
+ values of TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL are 0 and 1000
+ respectively."
+
+ Modify section 3.8.13 (Texture State and Proxy State) to add the new
+ state:
+
+ "Each set consists of ..., and a boolean flag indicating whether the
+ format and dimensions of the texture are immutable."
+
+ Add
+ "The initial value of TEXTURE_IMMUTABLE_FORMAT_EXT is FALSE."
+
+Additions to Chapter 4 of the OpenGL 3.2 Core Profile Specification
+(Per-Fragment Operations and the Frame Buffer)
+
+ None
+
+Additions to Chapter 5 of the OpenGL 3.2 Compatibility Profile Specification
+(Special Functions)
+
+ In section 5.4.1 (Commands Not Usable in Display Lists), add
+ TexStorage* to the list of commands that cannot be used.
+
+Additions to Chapter 6 of the OpenGL 3.2 Core Profile Specification
+(State and State Requests)
+
+ Replace the following statement in 6.1.3 (Enumerated Queries):
+
+ "<value> must be one of the symbolic values in table 3.10."
+
+ with
+
+ "<value> must be TEXTURE_IMMUTABLE_FORMAT_EXT or one of the symbolic
+ values in table 3.22."
+
+Additions to the AGL/EGL/GLX/WGL Specifications
+
+ None
+
+Additions to OES_compressed_ETC1_RGB8_texture
+
+ Add the following to the additions to Chapter 3:
+
+ "Since ETC1 images are easily edited along 4x4 texel boundaries, the
+ limitations on CompressedTexSubImage2D are relaxed.
+ CompressedTexSubImage2D will result in an INVALID_OPERATION error
+ only if one of the following conditions occurs:
+
+ * <width> is not a multiple of four, and <width> plus <xoffset> is not
+ equal to the texture width;
+
+ * <height> is not a multiple of four, and <height> plus <yoffset> is
+ not equal to the texture height; or
+
+ * <xoffset> or <yoffset> is not a multiple of four.
+
+ Remove CompressedTexSubImage2D from this error:
+
+ "INVALID_OPERATION is generated by CompressedTexSubImage2D,
+ TexSubImage2D, or CopyTexSubImage2D if the texture image <level>
+ bound to <target> has internal format ETC1_RGB8_OES."
+
+ Add the following error:
+
+ "INVALID_OPERATION is generated by CompressedTexSubImage2D
+ if the region to be modified is not aligned to block boundaries
+ (refer to the extension text for details)."
+
+Additions to AMD_compressed_ATC_texture and AMD_compressed_3DC_texture:
+
+ Apply the same changes as for OES_compressed_ETC1_RGB8_texture
+ above, substituting the appropriate internal format tokens from
+ these extensions.
+
+Dependencies on EXT_direct_state_access
+
+ If EXT_direct_state_access is not present, references to
+ TextureStorage* should be ignored.
+
+Dependencies on OpenGL ES
+
+ On OpenGL ES without extensions introducing TEXTURE_MAX_LEVEL,
+ mipmapped textures specified with TexStorage are required to have a
+ full set of mipmaps. If TEXTURE_MAX_LEVEL is not supported, this
+ extension is modified as follows:
+
+ - Where an upper bound is placed on <levels> in this extension (i.e.
+ the maximum number of mipmap levels for a texture of the given
+ target and dimensions), an INVALID_OPERATION error is generated if
+ <levels> is neither 1 nor this upper bound.
+ - q (the effective maximum number of levels) is redefined to clamp
+ to the number of levels present in immutable-format textures.
+
+ OpenGL ES does not accept sized internal formats (e.g., RGBA8) and
+ instead derives an internal format from the <format> and <type>
+ parameters of TexImage2D. Since TexStorage* does not specify texel
+ data, the API doesn't include <format> and <type> parameters.
+ On an OpenGL ES implementation, the values in the <internalformat>
+ column in the tables below are accepted as <internalformat>
+ parameters, and base internal formats are not accepted. The
+ TexImage* calls in the TexStorage* pseudocode are modified so that
+ the <internalformat>, <format> and <type> parameters are
+ taken from the <format>, <format> and <type> columns (respectively)
+ in the tables below, according to the <internalformat>
+ specified in the TexStorage* command.
+
+ <internalformat> <format> <type>
+ ---------------- -------- ------
+ RGB565 RGB UNSIGNED_SHORT_5_6_5
+ RGBA4 RGBA UNSIGNED_SHORT_4_4_4_4
+ RGB5_A1 RGBA UNSIGNED_SHORT_5_5_5_1
+ RGB8_OES RGB UNSIGNED_BYTE
+ RGBA8_OES RGBA UNSIGNED_BYTE
+ LUMINANCE8_ALPHA8_EXT LUMINANCE_ALPHA UNSIGNED_BYTE
+ LUMINANCE8_EXT LUMINANCE UNSIGNED_BYTE
+ ALPHA8_EXT ALPHA UNSIGNED_BYTE
+
+ If OES_depth_texture is supported:
+
+ <internalformat> <format> <type>
+ ---------------- -------- ------
+ DEPTH_COMPONENT16_OES DEPTH_COMPONENT UNSIGNED_SHORT
+ DEPTH_COMPONENT32_OES DEPTH_COMPONENT UNSIGNED_INT
+
+ If OES_packed_depth_stencil is supported:
+
+ <internalformat> <format> <type>
+ ---------------- -------- ------
+ DEPTH24_STENCIL8_OES DEPTH_STENCIL_OES UNSIGNED_INT
+
+ If OES_texture_float is supported:
+
+ <internalformat> <format> <type>
+ ---------------- -------- ------
+ RGBA32F_EXT RGBA FLOAT
+ RGB32F_EXT RGB FLOAT
+ LUMINANCE_ALPHA32F_EXT LUMINANCE_ALPHA FLOAT
+ LUMINANCE32F_EXT LUMINANCE FLOAT
+ ALPHA32F_EXT ALPHA FLOAT
+
+ If OES_texture_half_float is supported:
+
+ <internalformat> <format> <type>
+ ---------------- -------- ------
+ RGBA16F_EXT RGBA HALF_FLOAT_OES
+ RGB16F_EXT RGB HALF_FLOAT_OES
+ LUMINANCE_ALPHA16F_EXT LUMINANCE_ALPHA HALF_FLOAT_OES
+ LUMINANCE16F_EXT LUMINANCE HALF_FLOAT_OES
+ ALPHA16F_EXT ALPHA HALF_FLOAT_OES
+
+ If EXT_texture_type_2_10_10_10_REV is supported:
+
+ <internalformat> <format> <type>
+ ---------------- -------- ------
+ RGB10_A2_EXT RGBA UNSIGNED_INT_2_10_10_10_REV_EXT
+ RGB10_EXT RGB UNSIGNED_INT_2_10_10_10_REV_EXT
+
+ If EXT_texture_format_BGRA8888 is supported:
+
+ <internalformat> <format> <type>
+ ---------------- -------- ------
+ BGRA8_EXT BGRA_EXT UNSIGNED_BYTE
+
+
+Dependencies on texture targets
+
+ If a particular texture target is not supported by the
+ implementation, passing it as a <target> to TexStorage* will
+ generate an INVALID_ENUM error. If as a result, any of the commands
+ defined in this extension would no longer have any valid <target>,
+ all references to the command should be ignored.
+
+ In particular, note that OpenGL ES 1.x/2.0 do not have proxy textures,
+ 1D textures, or 3D textures, and thus only the TexStorage2DEXT
+ entry point is required. If OES_texture_3D is supported, the
+ TexStorage3DEXT entry point is also required.
+
+Dependencies on OES_texture_npot
+
+ If OpenGL ES 2.0 or APPLE_texture_2D_limited_npot is present but
+ OES_texture_npot is not present, then INVALID_OPERATION is
+ generated by TexStorage* and TexStorage3DEXT if <levels> is
+ not one and <width>, <height> or <depth> is not a power of
+ two.
+
+Dependencies on WGL_ARB_render_texture, GLX_EXT_texture_from_pixmap, EGL
+1.4 and GL_OES_EGL_image
+
+ The commands eglBindTexImage, wglBindTexImageARB, glXBindTexImageEXT or
+ EGLImageTargetTexture2DOES are not permitted on an immutable-format
+ texture.
+ They will generate the following errors:
+ - EGLImageTargetTexture2DOES: INVALID_OPERATION
+ - eglBindTexImage: EGL_BAD_MATCH
+ - wglBindTexImage: ERROR_INVALID_OPERATION
+ - glXBindTexImageEXT: BadMatch
+
+Dependencies on OES_compressed_paletted_texture
+
+ The compressed texture formats exposed by
+ OES_compressed_paletted_texture are not supported by TexStorage*.
+ Passing one of these tokens to TexStorage* will generate an
+ INVALID_ENUM error.
+
+Errors
+
+ Note that dependencies above modify the errors.
+
+ If TexStorage* is called with a <width>, <height>, <depth> or
+ <levels> parameter that is less than one, then the error
+ INVALID_VALUE is generated.
+
+ If the <target> parameter to TexStorage1DEXT is not
+ [PROXY_]TEXTURE_1D, then the error INVALID_ENUM is generated.
+
+ If the <target> parameter to TexStorage2DEXT is not
+ [PROXY_]TEXTURE_2D, [PROXY_]TEXTURE_CUBE_MAP,
+ [PROXY_]TEXTURE_RECTANGLE or [PROXY_]TEXTURE_1D_ARRAY, then the
+ error INVALID_ENUM is generated.
+
+ If the <target> parameter to TexStorage3DEXT is not
+ [PROXY_]TEXTURE_3D, [PROXY_]TEXTURE_2D_ARRAY or
+ [PROXY_]TEXTURE_CUBE_MAP_ARRAY then the error INVALID_ENUM is
+ generated.
+
+ If the <levels> parameter to TexStorage* is greater than the
+ <target>-specific value listed below then the error
+ INVALID_OPERATION is generated:
+ [PROXY_]TEXTURE_{1D,1D_ARRAY}:
+ floor(log_2(width)) + 1
+ [PROXY_]TEXTURE_{2D,2D_ARRAY,CUBE_MAP,CUBE_MAP_ARRAY}:
+ floor(log_2(max(width, height))) + 1
+ [PROXY_]TEXTURE_3D:
+ floor(log_2(max(width, height, depth))) + 1
+ [PROXY_]TEXTURE_RECTANGLE:
+ 1
+
+ If the default texture object is bound to the <target> passed to
+ TexStorage*, then the error INVALID_OPERATION is generated.
+
+ If the <target> parameter to TextureStorage* does not match the
+ dimensionality of <texture>, then the error INVALID_OPERATION is
+ generated.
+
+ If the <texture> parameter to TextureStorage* is zero, then the
+ INVALID_VALUE is generated.
+
+ If any pseudo-code listed in this extension would generate an error,
+ then that error is generated.
+
+ Calling any of the following functions on a texture for which
+ TEXTURE_IMMUTABLE_FORMAT_EXT is TRUE will generate an
+ INVALID_OPERATION error:
+ - TexImage*
+ - CompressedTexImage*
+ - CopyTexImage*
+
+New State
+
+ Additions to Table 6.8 Textures (state per texture object)
+
+ Initial
+ Get Value Type Get Command Value Description Sec.
+ --------- ---- ----------- ------- ----------- ----
+ TEXTURE_IMMUTABLE_FORMAT_EXT B GetTexParameter FALSE Size and format immutable 2.6
+
+New Implementation Dependent State
+
+ None
+
+Issues
+
+ 1. What should this extension be called?
+
+ RESOLVED: EXT_texture_storage is chosen for consistency with the
+ glRenderbufferStorage entry point.
+
+ 2. Should TexStorage* accept a border parameter?
+
+ RESOLVED: no.
+
+ DISCUSSION: Currently it does not, since borders are a deprecated
+ feature which is not supported by all hardware. Users of the
+ compatibility profile can continue to use the existing texture
+ specification functions, but there is an argument that users of
+ compatibility profile may also want to use this extension.
+
+ 3. What is the correct error when <levels> specifies a partial
+ mipmap pyramid for OpenGL ES?
+
+ RESOLVED: INVALID_OPERATION, since it is an interaction between
+ parameters rather than a single value being invalid. It also makes
+ sense to relax this condition for desktop GL where it makes sense to
+ use a truncated pyramid with TEXTURE_MAX_LEVEL.
+
+ 4. Should use of these entry-points make the metadata (format and
+ dimensions) immutable?
+
+ RESOLVED: Yes.
+
+ DISCUSSION: The benefits of knowing metadata can't change will
+ probably outweigh the extra cost of checking the
+ TEXTURE_IMMUTABLE_FORMAT_EXT flag on each texture specification
+ call.
+
+ 5. Should it be legal to completely replace the texture using a new call
+ to TexStorage*?
+
+ RESOLVED. It will not be allowed.
+
+ DISCUSSION: This is useful to invalidate all levels of a texture.
+ Allowing the metadata to be changed here seems easier than trying to
+ define a portable definition of what it means to change the metadata
+ (e.g. what if you used an unsized internal format the first time and
+ the corresponding sized internal format the second time, or vice
+ versa)?
+
+ However, while this is largely similar to deleting the old texture
+ object and replacing it with a new one, it does lose some of the
+ advantages of immutability. Specifically, because doing so does not
+ reset bindings, it doesn't allow a migration path to an API that
+ validates the texture format at bind time.
+
+ 6. Should it be legal to use TexImage* after TexStorage* if it doesn't
+ affect the metadata?
+
+ RESOLVED: No.
+
+ DISCUSSION: A potential use case is to allow a single level of a
+ texture to be invalidated using a NULL pointer. However, as noted
+ above it is non-trivial to determine what constitutes a change.
+
+ 7. How does this extension interact with APPLE_texture_2D_limited_npot?
+
+ RESOLVED. APPLE_texture_2D_limited_npot is equivalent to the NPOT
+ support in OpenGL ES 2.0.
+
+ 8. Should this extension be written to work with desktop OpenGL?
+
+ RESOLVED: Yes.
+
+ DISCUSSION: There has been been interest and it will future-proof it
+ against further additions to OpenGL ES.
+
+ 9. Which texture targets should be supported?
+
+ RESOLVED. All targets except multisample and buffer textures are
+ supported.
+
+ Initially all targets except TEXTURE_BUFFER were supported. It was
+ noted that the entrypoints for multisample targets added no useful
+ functionality, since multisample textures have no completeness
+ checks beyond being non-empty.
+
+ Rectangle textures have completeness checks to prevent filtering of
+ integer textures. However, since we decided to only force mipmap
+ completeness, this becomes less useful.
+
+ 10. Should this extension support proxy textures?
+
+ RESOLVED: Yes.
+
+ DISCUSSION: It should be orthogonal.
+
+ 11. Are the <format> and <type> parameters necessary?
+
+ RESOLVED. No, they will be removed.
+
+ DISCUSSION: For OpenGL ES the type parameter was necessary to
+ determine the precision of the texture, but this can be solved by
+ having these functions accept sized internal formats (which are
+ already accepted by renderbuffers).
+
+ 12. Should it be legal to make the default texture (id 0)
+ immutable-format?
+
+ RESOLVED: No.
+
+ DISCUSSION: This would make it impossible to restore the context to
+ it's default state, which is deemed undesirable. There is no good
+ reason not to use named texture objects.
+
+ 13. Should we try to guarantee that textures made through this path
+ will always be complete?
+
+ RESOLVED: It should be guaranteed that the texture will be mipmap
+ complete.
+
+ DISCUSSION: Future separation between images and samplers will still
+ allow users to create combinations that are invalid, but
+ constraining the simple cases will make these APIs easier to use for
+ beginners.
+
+ 14. Should these functions use a EXT_direct_state_access approach to
+ specifying the texture objects?
+
+ UNRESOLVED.
+
+ DISCUSSION: as a standalone extension, no DSA-like functions will be
+ added. However, interactions with EXT_direct_state_access and
+ ARB_direct_state_access need to be resolved.
+
+ 15. Should these functions accept generic compressed formats?
+
+ RESOLVED: Yes. Note that the spec language will need to be modified
+ to allow this for ES, since the pseudocode is written in terms of
+ TexImage2D, which does not allow compressed texture formats in ES.
+ See also issues 23 and 27.
+
+ 16. How should completeness be forced when TEXTURE_MAX_LEVEL is not
+ present?
+
+ RESOLVED. The maximum level q will be redefined to clamp to the
+ highest level available.
+
+ DISCUSSION: A single-level texture can be made complete either by
+ making it mipmap complete (by setting TEXTURE_MAX_LEVEL to 0) or by
+ turning off mipmapping (by choose an appropriate minification
+ filter).
+
+ Some options:
+
+ A: Specify that TexStorage* changes the default minification filter
+ for OpenGL ES. This makes it awkward to add TEXTURE_MAX_LEVEL
+ support to OpenGL ES later, since switching to match GL would break
+ compatibility. The two mechanisms also do not give identical
+ results, since the magnification threshold depends on the
+ minification filter.
+
+ B: Specify that the texture behaves as though TEXTURE_MAX_LEVEL were
+ zero. To specify this properly probably requires fairly intrusive
+ changes to the OpenGL ES full specification to add back all the
+ language relating to the max level. It also does not solve the
+ similar problem of what to do with NPOT textures; and it may have
+ hardware impacts due to the change in the min/mag crossover.
+
+ C: Specify that TexStorage* changes the default minification filter
+ for all implementations when a single-level texture is specified.
+ This may be slightly counter-intuitive to desktop GL users, but will
+ give consistent behaviour across variants of GL and avoids changing
+ the functional behaviour of this extension based on the presence or
+ absence of some other feature.
+
+ Currently B is specified. This has potential hardware implications
+ for OpenGL ES because of the effect of the minification filter on
+ the min/mag crossover. However, C has potential hardware implications
+ for OpenGL due to the separation of texture and sampler state.
+
+ 17. How should completeness be forced when only ES2-style NPOT is
+ available?
+
+ RESOLVED. It is not worth trying to do this, in light of issue 13.
+
+ Previous revisions of this extension overrode the minification
+ filter and wrap modes, but that is no longer the case. Since
+ OES_texture_npot removes the caveats on NPOT textures anyway, it
+ might not be worth trying to "fix" this.
+
+ 18. For OpenGL ES, how do the new sized internal formats interact
+ with OES_required_internal_format?
+
+ RESOLVED.
+
+ If OES_required_internal_format is not present, then the
+ <internalformat> parameter is intended merely to indicate what the
+ corresponding <format> and <type> would have been, had TexImage*
+ been used instead. If OES_required_internal_format is present, then
+ it is intended that the <internalformat> will be interpreted as if
+ it had been passed directly to TexImage*.
+
+ 19. Should there be some hinting mechanism to indicate whether data
+ is coming immediately or later?
+
+ RESOLVED. No parameter is needed. An extension can be added to provide
+ a TexParameter value which is latched at TexStorage time.
+
+ DISCUSSION: Some members felt that this would be useful so that they
+ could defer allocation when suitable, particularly if higher-
+ resolution images will be streamed in later; or to choose a memory
+ type or layout appropriate to the usage. However, implementation
+ experience with BufferData is that developers frequently provide
+ wrong values and implementations have to guess anyway.
+
+ One option suggested was the <usage> parameter currently passed to
+ BufferData. Another option was to set it with TexParameter.
+
+ 20. How should this extension interact with
+ EGLImageTargetTexture2DOES, eglBindTexImage, glXBindTexImage and
+ wglBindTexImage?
+
+ RESOLVED. These functions will not be permitted after glTexStorage*.
+
+ Several options are possible:
+
+ A) Disallow these functions.
+ B) Allow them, but have them reset the TEXTURE_IMMUTABLE_FORMAT_EXT
+ flag.
+ C) Allow them unconditionally.
+
+ C would violate the design principle that the dimensions and format
+ of the mipmap array are immutable. B does not so much modify the
+ dimension and formats as replace them with an entirely different
+ set.
+
+ 21. Should there be a single function for specifying 1D, 2D and 3D
+ targets?
+
+ RESOLVED. No, we will stick with existing precedent.
+
+ 22. Is it possible to use GenerateMipmap with an incomplete mipmap
+ pyramid?
+
+ RESOLVED. Yes, because the effective max level is limited to the
+ levels that were specified, and so GenerateMipmap does not generate
+ any new levels.
+
+ However, to make automatic mipmap generation work, it is necessary
+ to redefine p rather than q, since automatic mipmap generation
+ ignores the max level.
+
+ 23. How should this extension interact with
+ OES_compressed_paletted_texture?
+
+ RESOLVED. Paletted textures will not be permitted, and will
+ generate INVALID_ENUM.
+
+ DISCUSSION: OES_compressed_paletted_texture supplies all the mipmaps
+ in a single function call, with the palette specified once. That's
+ incompatible with the upload model in this extension.
+
+ 24. How can ETC1 textures be used with this extension?
+
+ RESOLVED. Add language in this extension to allow subregion uploads
+ for ETC1.
+
+ DISCUSSION: GL_OES_compressed_ETC1_RGB8_texture doesn't allow
+ CompressedTexSubImage*, so it would be impossible to use this
+ extension with ETC1. This is seen as an oversight in the ETC1
+ extension. While it cannot be fixed in that extension (since it is
+ already shipping), this extension can add that capability.
+
+ 25. Should any other compressed formats be similarly modified?
+
+ RESOLVED. Yes, AMD_compressed_ATC_texture and
+ AMD_compressed_3DC_texture can be modified similarly to ETC1
+ (Maurice Ribble indicated that both formats use 4x4 blocks). Desktop
+ OpenGL requires that whole-image replacement is supported for any
+ compressed texture format, and the OpenGL ES extensions
+ EXT_texture_compression_dxt1 and IMG_texture_compression_pvrtc
+ already allow whole-image replacement, so it is not necessary to
+ modify them to be used with this extension.
+
+ 26. Should these commands be permitted in display lists?
+
+ RESOLVED. No.
+
+ DISCUSSION: Display lists are most useful for repeating commands,
+ and TexStorage* commands cannot be repeated because the first call
+ makes the format immutable.
+
+ 27. Should these commands accept unsized internal formats?
+
+ RESOLVED: No, for both OpenGL and OpenGL ES.
+
+ DISCUSSION: normally the <type> parameter to TexImage* can serve as
+ a hint to select a sized format (and in OpenGL ES, this is the only
+ mechanism available); since TexStorage* does not have a <type>
+ parameter, the implementation has no information on which to base a
+ decision.
+
+Revision History
+
+ Revision 24, 2011/11/11 (dgkoch)
+ - Mark complete. Clarify ES clarifications.
+
+ Revision 23, 2011/11/10 (dgkoch)
+ - Add GLES clarifcations and interactions with more GLES extensions
+
+ Revision 22, 2011/11/10 (bmerry)
+ - Update my contact details
+
+ Revision 21, 2011/07/25 (bmerry)
+ - Remove dangling references to MultiTexStorage in Errors section
+
+ Revision 20, 2011/07/21 (bmerry)
+ - Remove dangling reference to <samples> in Errors section
+
+ Revision 19, 2011/05/02 (Jon Leech)
+ - Assign enum value
+
+ Revision 18, 2011/01/24 (bmerry)
+ - Disallow unsized internal formats (oversight in revision 17).
+
+ Revision 17, 2011/01/24 (bmerry)
+ - Added and resolved issue 26.
+ - Split issue 27 out from issue 15.
+ - Disallow TexStorage* in display lists.
+ - Use the term "immutable-format" consistently (bug 7281).
+
+ Revision 16, 2010/11/23 (bmerry)
+ - Disallowed TexStorage on an immutable-format texture
+ (resolves issue 5).
+ - Deleted MultiTexStorage* commands (other DSA functions still
+ unresolved).
+ - Some minor wording changes suggested by Pat Brown (bug 7002).
+
+ Revision 15, 2010/11/09 (bmerry)
+ - Reopened issue 5.
+ - Reopened issue 14, pending stabilisation of
+ ARB_direct_state_access.
+ - Marked issue 9 resolved, pending any objections.
+ - Fix references to no object being bound (was meant to refer to
+ the default object).
+ - Adding missing pseudocode for TEXTURE_1D_ARRAY.
+ - Corrected TEXTURE_2D_ARRAY -> TEXTURE_1D_ARRAY in error checks.
+ - Changed "levels... are removed" to "levels... are reset to their
+ init state", since desktop GL has per-level state apart from the
+ texels.
+ - Miscellaneous wording fixes.
+
+ Revision 14, 2010/09/25 (bmerry)
+ - Add issues 24-25 and alterations to
+ OES_compressed_ETC1_RGB8_texture, AMD_compressed_ATC_texture and
+ AMD_compressed_3DC_texture.
+
+ Revision 13, 2010/09/19 (bmerry)
+ - Two typo fixes from Daniel Koch
+
+ Revision 12, 2010/09/18 (bmerry)
+ - Changed resolution to issue 20
+ - Added and resolved issue 23
+ - Added explanation of how to upload data (in overview)
+ - Added spec language to implement resolution to issue 15
+
+ Revision 11, 2010/07/21 (bmerry)
+ - Resolved issue 16
+ - Reopen issue 20
+ - Fix some typos
+
+ Revision 10, 2010/07/15 (bmerry)
+ - Update some issues to match core text
+ - Resolved issue 17
+
+ Revision 9, 2010/05/24 (bmerry)
+ - Marked issue 2 as resolved
+ - Resolved issue 19 (as no change)
+ - Resolved issue 20
+ - Add issues 21-22
+ - Add in spec language to forbid use on default textures
+ - Redefine level_base, level_max to be clamped forms of
+ TEXTURE_BASE_LEVEL/TEXTURE_MAX_LEVEL when using immutable
+ textures
+ - Redefine p to also be clamped to the provided levels for
+ immutable textures, to support automatic mipmap generation
+ - Removed multisample functions
+ - Removed language stating that texture parameters were reset to
+ defaults
+
+ Revision 8, 2010/05/18 (bmerry)
+ - Added issue about EGLimage
+ - Marked issue 14 as resolved
+
+ Revision 7, 2010/05/04 (bmerry)
+ - Removed some lingering <format>, <type> parameters to the new
+ functions that should have been removed in revision 4
+ - Trivial typo fixes
+
+ Revision 6, 2010/02/18 (bmerry)
+ - Resolved issues 5, 6 and 18
+ - Added MultiTexStorage* functions for DSA interaction
+ - Added error for texture-target mismatch in DSA
+ - Allowed TexStorage* to be called again
+
+ Revision 5, 2010/01/25 (bmerry)
+ - Added to contributors list
+ - Require OpenGL 1.2, to simplify interactions with
+ TEXTURE_BASE_LEVEL/TEXTURE_MAX_LEVEL and CLAMP_TO_EDGE
+ - Change default wrap modes to always be CLAMP_TO_EDGE
+ - Change default filters to always be NEAREST
+ - Moved language about generating new levels into an interaction,
+ since it can only happen on OpenGL ES
+ - Added interaction with EXT_direct_state_access
+ - Added extra <internalformats> for GL ES when OES_depth_texture,
+ OES_packed_depth_stencil and EXT_texture_type_2_10_10_10_REV are
+ present.
+ - Minor non-functional wording fixes and typos
+ - Resolved issue 16
+ - Added issues 17-19
+
+ Revision 4, 2010/01/13 (bmerry)
+ - Changed suffix from ARM to EXT
+ - Added list of contributors
+ - Added language to force the texture to always be complete
+ - Removed <format> and <type> arguments
+ - Added issues 14-16
+ - Reopened issue 2
+ - Reformatted issues to separate resolution and discussion
+ - Resolved issues 1, 9 and 11-13
+ - Fixed the max number of levels in a cube map array
+
+ Revision 3, 2009/12/17 (bmerry)
+ - Added missing vendor suffix to TEXTURE_IMMUTABLE_FORMAT_ARM
+ - Rewritten to against desktop OpenGL
+ - Added prototypes for 1D and multisample storage functions
+ - Added issues 8-13
+
+ Revision 2, 2009/08/20 (bmerry)
+ - Resolved issue 2 (no border parameter)
+ - Resolved issue 4 (metadata becomes immutable)
+ - Added interaction with OES_texture_cube_map
+ - Added error if width != height in a cube map
+ - Added issues 5-7
+
+ Revision 1, 2009/05/06 (bmerry)
+ - First draft
diff --git a/include/EGL/egl.h b/include/EGL/egl.h
new file mode 100644
index 00000000..99ea342a
--- /dev/null
+++ b/include/EGL/egl.h
@@ -0,0 +1,329 @@
+/* -*- mode: c; tab-width: 8; -*- */
+/* vi: set sw=4 ts=8: */
+/* Reference version of egl.h for EGL 1.4.
+ * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $
+ */
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#ifndef __egl_h_
+#define __egl_h_
+
+/* All platform-dependent types and macro boilerplate (such as EGLAPI
+ * and EGLAPIENTRY) should go in eglplatform.h.
+ */
+#include <EGL/eglplatform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* EGL Types */
+/* EGLint is defined in eglplatform.h */
+typedef unsigned int EGLBoolean;
+typedef unsigned int EGLenum;
+typedef void *EGLConfig;
+typedef void *EGLContext;
+typedef void *EGLDisplay;
+typedef void *EGLSurface;
+typedef void *EGLClientBuffer;
+
+/* EGL Versioning */
+#define EGL_VERSION_1_0 1
+#define EGL_VERSION_1_1 1
+#define EGL_VERSION_1_2 1
+#define EGL_VERSION_1_3 1
+#define EGL_VERSION_1_4 1
+
+/* EGL Enumerants. Bitmasks and other exceptional cases aside, most
+ * enums are assigned unique values starting at 0x3000.
+ */
+
+/* EGL aliases */
+#define EGL_FALSE 0
+#define EGL_TRUE 1
+
+/* Out-of-band handle values */
+#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
+#define EGL_NO_CONTEXT ((EGLContext)0)
+#define EGL_NO_DISPLAY ((EGLDisplay)0)
+#define EGL_NO_SURFACE ((EGLSurface)0)
+
+/* Out-of-band attribute value */
+#define EGL_DONT_CARE ((EGLint)-1)
+
+/* Errors / GetError return values */
+#define EGL_SUCCESS 0x3000
+#define EGL_NOT_INITIALIZED 0x3001
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT 0x3006
+#define EGL_BAD_CURRENT_SURFACE 0x3007
+#define EGL_BAD_DISPLAY 0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300A
+#define EGL_BAD_NATIVE_WINDOW 0x300B
+#define EGL_BAD_PARAMETER 0x300C
+#define EGL_BAD_SURFACE 0x300D
+#define EGL_CONTEXT_LOST 0x300E /* EGL 1.1 - IMG_power_management */
+
+/* Reserved 0x300F-0x301F for additional errors */
+
+/* Config attributes */
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_RED_SIZE 0x3024
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_CONFIG_CAVEAT 0x3027
+#define EGL_CONFIG_ID 0x3028
+#define EGL_LEVEL 0x3029
+#define EGL_MAX_PBUFFER_HEIGHT 0x302A
+#define EGL_MAX_PBUFFER_PIXELS 0x302B
+#define EGL_MAX_PBUFFER_WIDTH 0x302C
+#define EGL_NATIVE_RENDERABLE 0x302D
+#define EGL_NATIVE_VISUAL_ID 0x302E
+#define EGL_NATIVE_VISUAL_TYPE 0x302F
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_TRANSPARENT_TYPE 0x3034
+#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
+#define EGL_TRANSPARENT_RED_VALUE 0x3037
+#define EGL_NONE 0x3038 /* Attrib list terminator */
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
+#define EGL_MIN_SWAP_INTERVAL 0x303B
+#define EGL_MAX_SWAP_INTERVAL 0x303C
+#define EGL_LUMINANCE_SIZE 0x303D
+#define EGL_ALPHA_MASK_SIZE 0x303E
+#define EGL_COLOR_BUFFER_TYPE 0x303F
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_MATCH_NATIVE_PIXMAP 0x3041 /* Pseudo-attribute (not queryable) */
+#define EGL_CONFORMANT 0x3042
+
+/* Reserved 0x3041-0x304F for additional config attributes */
+
+/* Config attribute values */
+#define EGL_SLOW_CONFIG 0x3050 /* EGL_CONFIG_CAVEAT value */
+#define EGL_NON_CONFORMANT_CONFIG 0x3051 /* EGL_CONFIG_CAVEAT value */
+#define EGL_TRANSPARENT_RGB 0x3052 /* EGL_TRANSPARENT_TYPE value */
+#define EGL_RGB_BUFFER 0x308E /* EGL_COLOR_BUFFER_TYPE value */
+#define EGL_LUMINANCE_BUFFER 0x308F /* EGL_COLOR_BUFFER_TYPE value */
+
+/* More config attribute values, for EGL_TEXTURE_FORMAT */
+#define EGL_NO_TEXTURE 0x305C
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_RGBA 0x305E
+#define EGL_TEXTURE_2D 0x305F
+
+/* Config attribute mask bits */
+#define EGL_PBUFFER_BIT 0x0001 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_PIXMAP_BIT 0x0002 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_WINDOW_BIT 0x0004 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */
+
+#define EGL_OPENGL_ES_BIT 0x0001 /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENVG_BIT 0x0002 /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_ES2_BIT 0x0004 /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_BIT 0x0008 /* EGL_RENDERABLE_TYPE mask bits */
+
+/* QueryString targets */
+#define EGL_VENDOR 0x3053
+#define EGL_VERSION 0x3054
+#define EGL_EXTENSIONS 0x3055
+#define EGL_CLIENT_APIS 0x308D
+
+/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */
+#define EGL_HEIGHT 0x3056
+#define EGL_WIDTH 0x3057
+#define EGL_LARGEST_PBUFFER 0x3058
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_TARGET 0x3081
+#define EGL_MIPMAP_TEXTURE 0x3082
+#define EGL_MIPMAP_LEVEL 0x3083
+#define EGL_RENDER_BUFFER 0x3086
+#define EGL_VG_COLORSPACE 0x3087
+#define EGL_VG_ALPHA_FORMAT 0x3088
+#define EGL_HORIZONTAL_RESOLUTION 0x3090
+#define EGL_VERTICAL_RESOLUTION 0x3091
+#define EGL_PIXEL_ASPECT_RATIO 0x3092
+#define EGL_SWAP_BEHAVIOR 0x3093
+#define EGL_MULTISAMPLE_RESOLVE 0x3099
+
+/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_SINGLE_BUFFER 0x3085
+
+/* OpenVG color spaces */
+#define EGL_VG_COLORSPACE_sRGB 0x3089 /* EGL_VG_COLORSPACE value */
+#define EGL_VG_COLORSPACE_LINEAR 0x308A /* EGL_VG_COLORSPACE value */
+
+/* OpenVG alpha formats */
+#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B /* EGL_ALPHA_FORMAT value */
+#define EGL_VG_ALPHA_FORMAT_PRE 0x308C /* EGL_ALPHA_FORMAT value */
+
+/* Constant scale factor by which fractional display resolutions &
+ * aspect ratio are scaled when queried as integer values.
+ */
+#define EGL_DISPLAY_SCALING 10000
+
+/* Unknown display resolution/aspect ratio */
+#define EGL_UNKNOWN ((EGLint)-1)
+
+/* Back buffer swap behaviors */
+#define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */
+#define EGL_BUFFER_DESTROYED 0x3095 /* EGL_SWAP_BEHAVIOR value */
+
+/* CreatePbufferFromClientBuffer buffer types */
+#define EGL_OPENVG_IMAGE 0x3096
+
+/* QueryContext targets */
+#define EGL_CONTEXT_CLIENT_TYPE 0x3097
+
+/* CreateContext attributes */
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+
+/* Multisample resolution behaviors */
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */
+#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B /* EGL_MULTISAMPLE_RESOLVE value */
+
+/* BindAPI/QueryAPI targets */
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENVG_API 0x30A1
+#define EGL_OPENGL_API 0x30A2
+
+/* GetCurrentSurface targets */
+#define EGL_DRAW 0x3059
+#define EGL_READ 0x305A
+
+/* WaitNative engines */
+#define EGL_CORE_NATIVE_ENGINE 0x305B
+
+/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */
+#define EGL_COLORSPACE EGL_VG_COLORSPACE
+#define EGL_ALPHA_FORMAT EGL_VG_ALPHA_FORMAT
+#define EGL_COLORSPACE_sRGB EGL_VG_COLORSPACE_sRGB
+#define EGL_COLORSPACE_LINEAR EGL_VG_COLORSPACE_LINEAR
+#define EGL_ALPHA_FORMAT_NONPRE EGL_VG_ALPHA_FORMAT_NONPRE
+#define EGL_ALPHA_FORMAT_PRE EGL_VG_ALPHA_FORMAT_PRE
+
+/* EGL extensions must request enum blocks from the Khronos
+ * API Registrar, who maintains the enumerant registry. Submit
+ * a bug in Khronos Bugzilla against task "Registry".
+ */
+
+
+
+/* EGL Functions */
+
+EGLAPI EGLint EGLAPIENTRY eglGetError(void);
+
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy);
+
+EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
+ EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
+ EGLNativePixmapType pixmap,
+ const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval);
+
+
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_context,
+ const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx);
+
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx,
+ EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface,
+ EGLNativePixmapType target);
+
+/* This is a generic function pointer type, whose name indicates it must
+ * be cast to the proper type *and calling convention* before use.
+ */
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+
+/* Now, define eglGetProcAddress using the generic function ptr. type */
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
+ eglGetProcAddress(const char *procname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __egl_h_ */
diff --git a/include/EGL/eglext.h b/include/EGL/eglext.h
new file mode 100644
index 00000000..c06d4c08
--- /dev/null
+++ b/include/EGL/eglext.h
@@ -0,0 +1,354 @@
+#ifndef __eglext_h_
+#define __eglext_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2007-2012 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#include <EGL/eglplatform.h>
+
+/*************************************************************/
+
+/* Header file version number */
+/* Current version at http://www.khronos.org/registry/egl/ */
+/* $Revision: 16473 $ on $Date: 2012-01-04 02:20:48 -0800 (Wed, 04 Jan 2012) $ */
+#define EGL_EGLEXT_VERSION 11
+
+#ifndef EGL_KHR_config_attribs
+#define EGL_KHR_config_attribs 1
+#define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */
+#endif
+
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */
+#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */
+#define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */
+#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */
+#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */
+#define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */
+#define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */
+#define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */
+#define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */
+#define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface);
+#endif
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */
+typedef void *EGLImageKHR;
+#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0)
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+#endif
+
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 1
+#define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_renderbuffer_image
+#define EGL_KHR_gl_renderbuffer_image 1
+#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */
+#endif
+
+#if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */
+#ifndef EGL_KHR_reusable_sync
+#define EGL_KHR_reusable_sync 1
+
+typedef void* EGLSyncKHR;
+typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+
+#define EGL_SYNC_STATUS_KHR 0x30F1
+#define EGL_SIGNALED_KHR 0x30F2
+#define EGL_UNSIGNALED_KHR 0x30F3
+#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5
+#define EGL_CONDITION_SATISFIED_KHR 0x30F6
+#define EGL_SYNC_TYPE_KHR 0x30F7
+#define EGL_SYNC_REUSABLE_KHR 0x30FA
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 /* eglClientWaitSyncKHR <flags> bitfield */
+#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull
+#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0)
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif
+#endif
+
+#ifndef EGL_KHR_image_base
+#define EGL_KHR_image_base 1
+/* Most interfaces defined by EGL_KHR_image_pixmap above */
+#define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_image_pixmap
+#define EGL_KHR_image_pixmap 1
+/* Interfaces defined by EGL_KHR_image above */
+#endif
+
+#ifndef EGL_IMG_context_priority
+#define EGL_IMG_context_priority 1
+#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
+#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
+#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
+#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
+#endif
+
+#ifndef EGL_KHR_lock_surface2
+#define EGL_KHR_lock_surface2 1
+#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110
+#endif
+
+#ifndef EGL_NV_coverage_sample
+#define EGL_NV_coverage_sample 1
+#define EGL_COVERAGE_BUFFERS_NV 0x30E0
+#define EGL_COVERAGE_SAMPLES_NV 0x30E1
+#endif
+
+#ifndef EGL_NV_depth_nonlinear
+#define EGL_NV_depth_nonlinear 1
+#define EGL_DEPTH_ENCODING_NV 0x30E2
+#define EGL_DEPTH_ENCODING_NONE_NV 0
+#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3
+#endif
+
+#if KHRONOS_SUPPORT_INT64 /* EGLTimeNV requires 64-bit uint support */
+#ifndef EGL_NV_sync
+#define EGL_NV_sync 1
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6
+#define EGL_SYNC_STATUS_NV 0x30E7
+#define EGL_SIGNALED_NV 0x30E8
+#define EGL_UNSIGNALED_NV 0x30E9
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001
+#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull
+#define EGL_ALREADY_SIGNALED_NV 0x30EA
+#define EGL_TIMEOUT_EXPIRED_NV 0x30EB
+#define EGL_CONDITION_SATISFIED_NV 0x30EC
+#define EGL_SYNC_TYPE_NV 0x30ED
+#define EGL_SYNC_CONDITION_NV 0x30EE
+#define EGL_SYNC_FENCE_NV 0x30EF
+#define EGL_NO_SYNC_NV ((EGLSyncNV)0)
+typedef void* EGLSyncNV;
+typedef khronos_utime_nanoseconds_t EGLTimeNV;
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLSyncNV eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+EGLBoolean eglDestroySyncNV (EGLSyncNV sync);
+EGLBoolean eglFenceNV (EGLSyncNV sync);
+EGLint eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+EGLBoolean eglSignalSyncNV (EGLSyncNV sync, EGLenum mode);
+EGLBoolean eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#endif
+#endif
+
+#if KHRONOS_SUPPORT_INT64 /* Dependent on EGL_KHR_reusable_sync which requires 64-bit uint support */
+#ifndef EGL_KHR_fence_sync
+#define EGL_KHR_fence_sync 1
+/* Reuses most tokens and entry points from EGL_KHR_reusable_sync */
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0
+#define EGL_SYNC_CONDITION_KHR 0x30F8
+#define EGL_SYNC_FENCE_KHR 0x30F9
+#endif
+#endif
+
+#ifndef EGL_HI_clientpixmap
+#define EGL_HI_clientpixmap 1
+
+/* Surface Attribute */
+#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74
+/*
+ * Structure representing a client pixmap
+ * (pixmap's data is in client-space memory).
+ */
+struct EGLClientPixmapHI
+{
+ void* pData;
+ EGLint iWidth;
+ EGLint iHeight;
+ EGLint iStride;
+};
+
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI(EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap);
+#endif /* EGL_HI_clientpixmap */
+
+#ifndef EGL_HI_colorformats
+#define EGL_HI_colorformats 1
+/* Config Attribute */
+#define EGL_COLOR_FORMAT_HI 0x8F70
+/* Color Formats */
+#define EGL_COLOR_RGB_HI 0x8F71
+#define EGL_COLOR_RGBA_HI 0x8F72
+#define EGL_COLOR_ARGB_HI 0x8F73
+#endif /* EGL_HI_colorformats */
+
+#ifndef EGL_MESA_drm_image
+#define EGL_MESA_drm_image 1
+#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0 /* CreateDRMImageMESA attribute */
+#define EGL_DRM_BUFFER_USE_MESA 0x31D1 /* CreateDRMImageMESA attribute */
+#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2 /* EGL_IMAGE_FORMAT_MESA attribute value */
+#define EGL_DRM_BUFFER_MESA 0x31D3 /* eglCreateImageKHR target */
+#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4
+#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001 /* EGL_DRM_BUFFER_USE_MESA bits */
+#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002 /* EGL_DRM_BUFFER_USE_MESA bits */
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#endif
+
+#ifndef EGL_NV_post_sub_buffer
+#define EGL_NV_post_sub_buffer 1
+#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#endif
+
+#ifndef EGL_ANGLE_query_surface_pointer
+#define EGL_ANGLE_query_surface_pointer 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#endif
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#endif
+
+#ifndef EGL_ANGLE_software_display
+#define EGL_ANGLE_software_display 1
+#define EGL_SOFTWARE_DISPLAY_ANGLE ((EGLNativeDisplayType)-1)
+#endif
+
+#ifndef EGL_ANGLE_direct3d_display
+#define EGL_ANGLE_direct3d_display 1
+#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2)
+#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3)
+#endif
+
+#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
+#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
+#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
+#endif
+
+#ifndef EGL_NV_coverage_sample_resolve
+#define EGL_NV_coverage_sample_resolve 1
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131
+#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133
+#endif
+
+#if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */
+#ifndef EGL_NV_system_time
+#define EGL_NV_system_time 1
+
+typedef khronos_utime_nanoseconds_t EGLuint64NV;
+
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV(void);
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV(void);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void);
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void);
+#endif
+#endif
+
+#ifndef EGL_EXT_create_context_robustness
+#define EGL_EXT_create_context_robustness 1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
+#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/EGL/eglplatform.h b/include/EGL/eglplatform.h
new file mode 100644
index 00000000..34283f2e
--- /dev/null
+++ b/include/EGL/eglplatform.h
@@ -0,0 +1,129 @@
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions for egl.h
+ * $Revision: 12306 $ on $Date: 2010-08-25 09:51:28 -0700 (Wed, 25 Aug 2010) $
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "EGL" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+/* Macros used in EGL function prototype declarations.
+ *
+ * EGL functions should be prototyped as:
+ *
+ * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+ * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+ *
+ * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+ */
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#ifndef EGLAPIENTRY
+#define EGLAPIENTRY KHRONOS_APIENTRY
+#endif
+#define EGLAPIENTRYP EGLAPIENTRY*
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+ * are aliases of window-system-dependent types, such as X Display * or
+ * Windows Device Context. They must be defined in platform-specific
+ * code below. The EGL-prefixed versions of Native*Type are the same
+ * types, renamed in EGL 1.3 so all types in the API start with "EGL".
+ *
+ * Khronos STRONGLY RECOMMENDS that you use the default definitions
+ * provided below, since these changes affect both binary and source
+ * portability of applications using EGL running on different EGL
+ * implementations.
+ */
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+typedef HDC EGLNativeDisplayType;
+typedef HBITMAP EGLNativePixmapType;
+typedef HWND EGLNativeWindowType;
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativeWindowType;
+typedef void *EGLNativePixmapType;
+
+#elif defined(WL_EGL_PLATFORM)
+
+typedef struct wl_display *EGLNativeDisplayType;
+typedef struct wl_egl_pixmap *EGLNativePixmapType;
+typedef struct wl_egl_window *EGLNativeWindowType;
+
+#elif defined(__unix__) && !defined(ANDROID)
+
+/* X11 (tentative) */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap EGLNativePixmapType;
+typedef Window EGLNativeWindowType;
+
+#elif defined(ANDROID)
+
+struct egl_native_pixmap_t;
+
+typedef struct ANativeWindow* EGLNativeWindowType;
+typedef struct egl_native_pixmap_t* EGLNativePixmapType;
+typedef void* EGLNativeDisplayType;
+
+#else
+#error "Platform not recognized"
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType NativePixmapType;
+typedef EGLNativeWindowType NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+ * all legal attribute names and values passed into and out of EGL, whether
+ * their type is boolean, bitmask, enumerant (symbolic constant), integer,
+ * handle, or other. While in general a 32-bit integer will suffice, if
+ * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+ * integer type.
+ */
+typedef khronos_int32_t EGLint;
+
+#endif /* __eglplatform_h */
diff --git a/include/GLES2/gl2.h b/include/GLES2/gl2.h
new file mode 100644
index 00000000..e1d3b87c
--- /dev/null
+++ b/include/GLES2/gl2.h
@@ -0,0 +1,621 @@
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
+
+#include <GLES2/gl2platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+typedef void GLvoid;
+typedef char GLchar;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
diff --git a/include/GLES2/gl2ext.h b/include/GLES2/gl2ext.h
new file mode 100644
index 00000000..bad50f9c
--- /dev/null
+++ b/include/GLES2/gl2ext.h
@@ -0,0 +1,1550 @@
+#ifndef __gl2ext_h_
+#define __gl2ext_h_
+
+/* $Revision: 16482 $ on $Date:: 2012-01-04 13:44:55 -0500 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+# define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif
+
+/* GL_OES_depth_texture */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_SAMPLER_EXTERNAL_OES 0x8D66
+#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_UNSIGNED_INT 0x1405
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_TEXTURE_WRAP_R_OES 0x8072
+#define GL_TEXTURE_3D_OES 0x806F
+#define GL_TEXTURE_BINDING_3D_OES 0x806A
+#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
+#define GL_SAMPLER_3D_OES 0x8B5F
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4
+#endif
+
+/* GL_OES_texture_float */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_HALF_FLOAT_OES 0x8D61
+#endif
+
+/* GL_OES_texture_half_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_npot */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
+#endif
+
+/* GL_OES_vertex_half_float */
+/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6
+#define GL_INT_10_10_10_2_OES 0x8DF7
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif
+
+/* GL_AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_COUNTER_TYPE_AMD 0x8BC0
+#define GL_COUNTER_RANGE_AMD 0x8BC1
+#define GL_UNSIGNED_INT64_AMD 0x8BC2
+#define GL_PERCENTAGE_AMD 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
+#define GL_PERFMON_RESULT_AMD 0x8BC6
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_Z400_BINARY_AMD 0x8740
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56
+#define GL_MAX_SAMPLES_ANGLE 0x8D57
+#endif
+
+/* GL_ANGLE_pack_reverse_row_order */
+#ifndef GL_ANGLE_pack_reverse_row_order
+#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4
+#endif
+
+/* GL_ANGLE_texture_compression_dxt3 */
+#ifndef GL_ANGLE_texture_compression_dxt3
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2
+#endif
+
+/* GL_ANGLE_texture_compression_dxt5 */
+#ifndef GL_ANGLE_texture_compression_dxt5
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3
+#endif
+
+/* GL_ANGLE_translated_shader_source */
+#ifndef GL_ANGLE_translated_shader_source
+#define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0
+#endif
+
+/* GL_ANGLE_texture_usage */
+#ifndef GL_ANGLE_texture_usage
+#define GL_TEXTURE_USAGE_ANGLE 0x93A2
+#define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3
+#endif
+
+/* GL_ANGLE_instanced_arrays */
+#ifndef GL_ANGLE_instanced_arrays
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE
+#endif
+
+/* GL_ANGLE_program_binary */
+#ifndef GL_ANGLE_program_binary
+#define GL_PROGRAM_BINARY_ANGLE 0x93A6
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_RGB_422_APPLE 0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56
+#define GL_MAX_SAMPLES_APPLE 0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_MALI_SHADER_BINARY_ARM 0x8F60
+#endif
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_MIN_EXT 0x8007
+#define GL_MAX_EXT 0x8008
+#endif
+
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_RGBA16F_EXT 0x881A
+#define GL_RGB16F_EXT 0x881B
+#define GL_RG16F_EXT 0x822F
+#define GL_R16F_EXT 0x822D
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211
+#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F
+#define GL_PROGRAM_OBJECT_EXT 0x8B40
+#define GL_SHADER_OBJECT_EXT 0x8B48
+#define GL_BUFFER_OBJECT_EXT 0x9151
+#define GL_QUERY_OBJECT_EXT 0x9153
+#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154
+#endif
+
+/* GL_EXT_debug_marker */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_COLOR_EXT 0x1800
+#define GL_DEPTH_EXT 0x1801
+#define GL_STENCIL_EXT 0x1802
+#endif
+
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x9134
+#define GL_MAX_SAMPLES_EXT 0x9135
+#endif
+
+/* GL_EXT_multi_draw_arrays */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A
+#define GL_CURRENT_QUERY_EXT 0x8865
+#define GL_QUERY_RESULT_EXT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_BGRA_EXT 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
+#endif
+
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+/* reuse GL_NO_ERROR */
+#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253
+#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255
+#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
+#define GL_NO_RESET_NOTIFICATION_EXT 0x8261
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_VERTEX_SHADER_BIT_EXT 0x00000001
+#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002
+#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF
+#define GL_PROGRAM_SEPARABLE_EXT 0x8258
+#define GL_ACTIVE_PROGRAM_EXT 0x8259
+#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A
+#endif
+
+/* GL_EXT_shader_texture_lod */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C
+#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D
+#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_SRGB_EXT 0x8C40
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_RED_EXT 0x1903
+#define GL_RG_EXT 0x8227
+#define GL_R8_EXT 0x8229
+#define GL_RG8_EXT 0x822B
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
+#define GL_ALPHA8_EXT 0x803C
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_RGBA32F_EXT 0x8814
+#define GL_RGB32F_EXT 0x8815
+#define GL_ALPHA32F_EXT 0x8816
+#define GL_LUMINANCE32F_EXT 0x8818
+#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
+/* reuse GL_RGBA16F_EXT */
+#define GL_RGB16F_EXT 0x881B
+#define GL_ALPHA16F_EXT 0x881C
+#define GL_LUMINANCE16F_EXT 0x881E
+#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
+#define GL_RGB10_A2_EXT 0x8059
+#define GL_RGB10_EXT 0x8052
+#define GL_BGRA8_EXT 0x93A1
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_SHADER_BINARY_DMP 0x9250
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_SGX_PROGRAM_BINARY_IMG 0x9130
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA_IMG 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_SGX_BINARY_IMG 0x8C0A
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_RENDERBUFFER_SAMPLES_IMG 0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134
+#define GL_MAX_SAMPLES_IMG 0x9135
+#define GL_TEXTURE_SAMPLES_IMG 0x9136
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_COVERAGE_COMPONENT_NV 0x8ED0
+#define GL_COVERAGE_COMPONENT4_NV 0x8ED1
+#define GL_COVERAGE_ATTACHMENT_NV 0x8ED2
+#define GL_COVERAGE_BUFFERS_NV 0x8ED3
+#define GL_COVERAGE_SAMPLES_NV 0x8ED4
+#define GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5
+#define GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6
+#define GL_COVERAGE_AUTOMATIC_NV 0x8ED7
+#define GL_COVERAGE_BUFFER_BIT_NV 0x8000
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_NV 0x8824
+#define GL_DRAW_BUFFER0_NV 0x8825
+#define GL_DRAW_BUFFER1_NV 0x8826
+#define GL_DRAW_BUFFER2_NV 0x8827
+#define GL_DRAW_BUFFER3_NV 0x8828
+#define GL_DRAW_BUFFER4_NV 0x8829
+#define GL_DRAW_BUFFER5_NV 0x882A
+#define GL_DRAW_BUFFER6_NV 0x882B
+#define GL_DRAW_BUFFER7_NV 0x882C
+#define GL_DRAW_BUFFER8_NV 0x882D
+#define GL_DRAW_BUFFER9_NV 0x882E
+#define GL_DRAW_BUFFER10_NV 0x882F
+#define GL_DRAW_BUFFER11_NV 0x8830
+#define GL_DRAW_BUFFER12_NV 0x8831
+#define GL_DRAW_BUFFER13_NV 0x8832
+#define GL_DRAW_BUFFER14_NV 0x8833
+#define GL_DRAW_BUFFER15_NV 0x8834
+#define GL_COLOR_ATTACHMENT0_NV 0x8CE0
+#define GL_COLOR_ATTACHMENT1_NV 0x8CE1
+#define GL_COLOR_ATTACHMENT2_NV 0x8CE2
+#define GL_COLOR_ATTACHMENT3_NV 0x8CE3
+#define GL_COLOR_ATTACHMENT4_NV 0x8CE4
+#define GL_COLOR_ATTACHMENT5_NV 0x8CE5
+#define GL_COLOR_ATTACHMENT6_NV 0x8CE6
+#define GL_COLOR_ATTACHMENT7_NV 0x8CE7
+#define GL_COLOR_ATTACHMENT8_NV 0x8CE8
+#define GL_COLOR_ATTACHMENT9_NV 0x8CE9
+#define GL_COLOR_ATTACHMENT10_NV 0x8CEA
+#define GL_COLOR_ATTACHMENT11_NV 0x8CEB
+#define GL_COLOR_ATTACHMENT12_NV 0x8CEC
+#define GL_COLOR_ATTACHMENT13_NV 0x8CED
+#define GL_COLOR_ATTACHMENT14_NV 0x8CEE
+#define GL_COLOR_ATTACHMENT15_NV 0x8CEF
+#endif
+
+/* GL_EXT_draw_buffers */
+#ifndef GL_EXT_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_EXT 0x8824
+#define GL_DRAW_BUFFER0_EXT 0x8825
+#define GL_DRAW_BUFFER1_EXT 0x8826
+#define GL_DRAW_BUFFER2_EXT 0x8827
+#define GL_DRAW_BUFFER3_EXT 0x8828
+#define GL_DRAW_BUFFER4_EXT 0x8829
+#define GL_DRAW_BUFFER5_EXT 0x882A
+#define GL_DRAW_BUFFER6_EXT 0x882B
+#define GL_DRAW_BUFFER7_EXT 0x882C
+#define GL_DRAW_BUFFER8_EXT 0x882D
+#define GL_DRAW_BUFFER9_EXT 0x882E
+#define GL_DRAW_BUFFER10_EXT 0x882F
+#define GL_DRAW_BUFFER11_EXT 0x8830
+#define GL_DRAW_BUFFER12_EXT 0x8831
+#define GL_DRAW_BUFFER13_EXT 0x8832
+#define GL_DRAW_BUFFER14_EXT 0x8833
+#define GL_DRAW_BUFFER15_EXT 0x8834
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
+#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF
+/* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_READ_BUFFER_NV 0x0C02
+#endif
+
+/* GL_NV_read_buffer_front */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_compression_s3tc_update */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_npot_2D_mipmap */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_ALPHA_TEST_QCOM 0x0BC0
+#define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1
+#define GL_ALPHA_TEST_REF_QCOM 0x0BC2
+#endif
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_TEXTURE_WIDTH_QCOM 0x8BD2
+#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3
+#define GL_TEXTURE_DEPTH_QCOM 0x8BD4
+#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5
+#define GL_TEXTURE_FORMAT_QCOM 0x8BD6
+#define GL_TEXTURE_TYPE_QCOM 0x8BD7
+#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8
+#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9
+#define GL_TEXTURE_TARGET_QCOM 0x8BDA
+#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB
+#define GL_STATE_RESTORE 0x8BDC
+#endif
+
+/* GL_QCOM_extended_get2 */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_WRITEONLY_RENDERING_QCOM 0x8823
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001
+#define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002
+#define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004
+#define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008
+#define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010
+#define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020
+#define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040
+#define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080
+#define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100
+#define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200
+#define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400
+#define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800
+#define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000
+#define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000
+#define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000
+#define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000
+#define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000
+#define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000
+#define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000
+#define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000
+#define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000
+#define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000
+#define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000
+#define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000
+#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000
+#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000
+#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000
+#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000
+#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000
+#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000
+#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000
+#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_SHADER_BINARY_VIV 0x8FC4
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_depth_texture */
+#ifndef GL_OES_depth_texture
+#define GL_OES_depth_texture 1
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fragment_precision_high */
+#ifndef GL_OES_fragment_precision_high
+#define GL_OES_fragment_precision_high 1
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_OES_get_program_binary 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_OES_standard_derivatives 1
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_OES_texture_3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+
+/* GL_OES_texture_float */
+#ifndef GL_OES_texture_float
+#define GL_OES_texture_float 1
+#endif
+
+/* GL_OES_texture_float_linear */
+#ifndef GL_OES_texture_float_linear
+#define GL_OES_texture_float_linear 1
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_OES_texture_half_float 1
+#endif
+
+/* GL_OES_texture_half_float_linear */
+#ifndef GL_OES_texture_half_float_linear
+#define GL_OES_texture_half_float_linear 1
+#endif
+
+/* GL_OES_texture_npot */
+#ifndef GL_OES_texture_npot
+#define GL_OES_texture_npot 1
+#endif
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_OES_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array);
+GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays);
+GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays);
+GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array);
+#endif
+typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
+#endif
+
+/* GL_OES_vertex_half_float */
+#ifndef GL_OES_vertex_half_float
+#define GL_OES_vertex_half_float 1
+#endif
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_OES_vertex_type_10_10_10_2 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/* AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_AMD_program_binary_Z400 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_ANGLE_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_ANGLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+/* GL_ANGLE_pack_reverse_row_order */
+#ifndef GL_ANGLE_pack_reverse_row_order
+#define GL_ANGLE_pack_reverse_row_order 1
+#endif
+
+/* GL_ANGLE_texture_compression_dxt3 */
+#ifndef GL_ANGLE_texture_compression_dxt3
+#define GL_ANGLE_texture_compression_dxt3 1
+#endif
+
+/* GL_ANGLE_texture_compression_dxt5 */
+#ifndef GL_ANGLE_texture_compression_dxt5
+#define GL_ANGLE_texture_compression_dxt5 1
+#endif
+
+/* GL_ANGLE_translated_shader_source */
+#ifndef GL_ANGLE_translated_shader_source
+#define GL_ANGLE_translated_shader_source 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+#endif
+
+/* GL_ANGLE_texture_usage */
+#ifndef GL_ANGLE_texture_usage
+#define GL_ANGLE_texture_usage 1
+#endif
+
+/* GL_ANGLE_instanced_arrays */
+#ifndef GL_ANGLE_instanced_arrays
+#define GL_ANGLE_instanced_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE(GLuint index, GLuint divisor);
+GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+#endif
+typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor);
+typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_ARM_mali_shader_binary 1
+#endif
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#endif
+
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_EXT_color_buffer_half_float 1
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_EXT_debug_label 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+
+/* GL_EXT_debug_marker */
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void);
+#endif
+typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_EXT_discard_framebuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_EXT_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_EXT_occlusion_query_boolean 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids);
+GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids);
+GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id);
+GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id);
+GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target);
+GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params);
+#endif
+typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
+typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id);
+typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
+typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_EXT_read_format_bgra 1
+#endif
+
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+#define GL_EXT_robustness 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
+GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params);
+GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_EXT_separate_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program);
+GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program);
+GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings);
+GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines);
+GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines);
+GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
+typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
+typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
+typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint x, GLint y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+
+/* GL_EXT_shader_texture_lod */
+#ifndef GL_EXT_shader_texture_lod
+#define GL_EXT_shader_texture_lod 1
+#endif
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_EXT_shadow_samplers 1
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_EXT_sRGB 1
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 1
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_EXT_texture_rg 1
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_EXT_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_EXT_texture_type_2_10_10_10_REV 1
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_EXT_unpack_subimage 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_DMP_shader_binary 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_IMG_program_binary 1
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 1
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_IMG_shader_binary 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 1
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_IMG_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMG) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMG) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_NV_coverage_sample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
+GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
+typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_NV_depth_nonlinear 1
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_NV_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+#ifndef GL_EXT_draw_buffers
+#define GL_EXT_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersEXT (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_NV_fbo_color_attachments 1
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint);
+GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_NV_read_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode);
+#endif
+typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode);
+#endif
+
+/* GL_NV_read_buffer_front */
+#ifndef GL_NV_read_buffer_front
+#define GL_NV_read_buffer_front 1
+#endif
+
+/* GL_NV_read_depth */
+#ifndef GL_NV_read_depth
+#define GL_NV_read_depth 1
+#endif
+
+/* GL_NV_read_depth_stencil */
+#ifndef GL_NV_read_depth_stencil
+#define GL_NV_read_depth_stencil 1
+#endif
+
+/* GL_NV_read_stencil */
+#ifndef GL_NV_read_stencil
+#define GL_NV_read_stencil 1
+#endif
+
+/* GL_NV_texture_compression_s3tc_update */
+#ifndef GL_NV_texture_compression_s3tc_update
+#define GL_NV_texture_compression_s3tc_update 1
+#endif
+
+/* GL_NV_texture_npot_2D_mipmap */
+#ifndef GL_NV_texture_npot_2D_mipmap
+#define GL_NV_texture_npot_2D_mipmap 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_QCOM_alpha_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref);
+#endif
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_QCOM_extended_get 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures);
+GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params);
+#endif
+
+/* GL_QCOM_extended_get2 */
+#ifndef GL_QCOM_extended_get2
+#define GL_QCOM_extended_get2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program);
+GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 1
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_QCOM_writeonly_rendering 1
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_QCOM_tiled_rendering 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
+#endif
+typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_VIV_shader_binary 1
+#endif
+
+/* GL_ANGLE_program_binary */
+#ifndef GL_ANGLE_program_binary
+#define GL_ANGLE_program_binary 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2ext_h_ */
diff --git a/include/GLES2/gl2platform.h b/include/GLES2/gl2platform.h
new file mode 100644
index 00000000..c9fa3c4d
--- /dev/null
+++ b/include/GLES2/gl2platform.h
@@ -0,0 +1,30 @@
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_APICALL
+#define GL_APICALL KHRONOS_APICALL
+#endif
+
+#ifndef GL_APIENTRY
+#define GL_APIENTRY KHRONOS_APIENTRY
+#endif
+
+#endif /* __gl2platform_h_ */
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h
new file mode 100644
index 00000000..722ac649
--- /dev/null
+++ b/include/GLSLANG/ShaderLang.h
@@ -0,0 +1,446 @@
+//
+// 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.
+//
+#ifndef _COMPILER_INTERFACE_INCLUDED_
+#define _COMPILER_INTERFACE_INCLUDED_
+
+#if defined(COMPONENT_BUILD)
+#if defined(_WIN32) || defined(_WIN64)
+
+#if defined(COMPILER_IMPLEMENTATION)
+#define COMPILER_EXPORT __declspec(dllexport)
+#else
+#define COMPILER_EXPORT __declspec(dllimport)
+#endif // defined(COMPILER_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#define COMPILER_EXPORT __attribute__((visibility("default")))
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define COMPILER_EXPORT
+#endif
+
+#include "KHR/khrplatform.h"
+#include <stddef.h>
+
+//
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler.
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Version number for shader translation API.
+// It is incremented everytime the API changes.
+#define ANGLE_SH_VERSION 110
+
+//
+// The names of the following enums have been derived by replacing GL prefix
+// with SH. For example, SH_INFO_LOG_LENGTH is equivalent to GL_INFO_LOG_LENGTH.
+// The enum values are also equal to the values of their GL counterpart. This
+// is done to make it easier for applications to use the shader library.
+//
+typedef enum {
+ SH_FRAGMENT_SHADER = 0x8B30,
+ SH_VERTEX_SHADER = 0x8B31
+} ShShaderType;
+
+typedef enum {
+ SH_GLES2_SPEC = 0x8B40,
+ SH_WEBGL_SPEC = 0x8B41,
+
+ // The CSS Shaders spec is a subset of the WebGL spec.
+ //
+ // In both CSS vertex and fragment shaders, ANGLE:
+ // (1) Reserves the "css_" prefix.
+ // (2) Renames the main function to css_main.
+ // (3) Disables the gl_MaxDrawBuffers built-in.
+ //
+ // In CSS fragment shaders, ANGLE:
+ // (1) Disables the gl_FragColor built-in.
+ // (2) Disables the gl_FragData built-in.
+ // (3) Enables the css_MixColor built-in.
+ // (4) Enables the css_ColorMatrix built-in.
+ //
+ // After passing a CSS shader through ANGLE, the browser is expected to append
+ // a new main function to it.
+ // This new main function will call the css_main function.
+ // It may also perform additional operations like varying assignment, texture
+ // access, and gl_FragColor assignment in order to implement the CSS Shaders
+ // blend modes.
+ //
+ SH_CSS_SHADERS_SPEC = 0x8B42
+} ShShaderSpec;
+
+typedef enum {
+ SH_ESSL_OUTPUT = 0x8B45,
+ SH_GLSL_OUTPUT = 0x8B46,
+ SH_HLSL_OUTPUT = 0x8B47,
+ SH_HLSL9_OUTPUT = 0x8B47,
+ SH_HLSL11_OUTPUT = 0x8B48
+} ShShaderOutput;
+
+typedef enum {
+ SH_NONE = 0,
+ SH_INT = 0x1404,
+ SH_FLOAT = 0x1406,
+ SH_FLOAT_VEC2 = 0x8B50,
+ SH_FLOAT_VEC3 = 0x8B51,
+ SH_FLOAT_VEC4 = 0x8B52,
+ SH_INT_VEC2 = 0x8B53,
+ SH_INT_VEC3 = 0x8B54,
+ SH_INT_VEC4 = 0x8B55,
+ SH_BOOL = 0x8B56,
+ SH_BOOL_VEC2 = 0x8B57,
+ SH_BOOL_VEC3 = 0x8B58,
+ SH_BOOL_VEC4 = 0x8B59,
+ SH_FLOAT_MAT2 = 0x8B5A,
+ SH_FLOAT_MAT3 = 0x8B5B,
+ SH_FLOAT_MAT4 = 0x8B5C,
+ SH_SAMPLER_2D = 0x8B5E,
+ SH_SAMPLER_CUBE = 0x8B60,
+ SH_SAMPLER_2D_RECT_ARB = 0x8B63,
+ SH_SAMPLER_EXTERNAL_OES = 0x8D66
+} ShDataType;
+
+typedef enum {
+ SH_INFO_LOG_LENGTH = 0x8B84,
+ SH_OBJECT_CODE_LENGTH = 0x8B88, // GL_SHADER_SOURCE_LENGTH
+ SH_ACTIVE_UNIFORMS = 0x8B86,
+ SH_ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87,
+ SH_ACTIVE_ATTRIBUTES = 0x8B89,
+ SH_ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A,
+ SH_MAPPED_NAME_MAX_LENGTH = 0x6000,
+ SH_NAME_MAX_LENGTH = 0x6001,
+ SH_HASHED_NAME_MAX_LENGTH = 0x6002,
+ SH_HASHED_NAMES_COUNT = 0x6003,
+ SH_ACTIVE_UNIFORMS_ARRAY = 0x6004
+} ShShaderInfo;
+
+// Compile options.
+typedef enum {
+ SH_VALIDATE = 0,
+ SH_VALIDATE_LOOP_INDEXING = 0x0001,
+ SH_INTERMEDIATE_TREE = 0x0002,
+ SH_OBJECT_CODE = 0x0004,
+ SH_ATTRIBUTES_UNIFORMS = 0x0008,
+ SH_LINE_DIRECTIVES = 0x0010,
+ SH_SOURCE_PATH = 0x0020,
+ SH_MAP_LONG_VARIABLE_NAMES = 0x0040,
+ SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = 0x0080,
+
+ // This is needed only as a workaround for certain OpenGL driver bugs.
+ SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100,
+
+ // This is an experimental flag to enforce restrictions that aim to prevent
+ // timing attacks.
+ // It generates compilation errors for shaders that could expose sensitive
+ // texture information via the timing channel.
+ // To use this flag, you must compile the shader under the WebGL spec
+ // (using the SH_WEBGL_SPEC flag).
+ SH_TIMING_RESTRICTIONS = 0x0200,
+
+ // This flag prints the dependency graph that is used to enforce timing
+ // restrictions on fragment shaders.
+ // This flag only has an effect if all of the following are true:
+ // - The shader spec is SH_WEBGL_SPEC.
+ // - The compile options contain the SH_TIMING_RESTRICTIONS flag.
+ // - The shader type is SH_FRAGMENT_SHADER.
+ SH_DEPENDENCY_GRAPH = 0x0400,
+
+ // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
+ SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
+
+ // This flag ensures all indirect (expression-based) array indexing
+ // is clamped to the bounds of the array. This ensures, for example,
+ // that you cannot read off the end of a uniform, whether an array
+ // vec234, or mat234 type. The ShArrayIndexClampingStrategy enum,
+ // specified in the ShBuiltInResources when constructing the
+ // compiler, selects the strategy for the clamping implementation.
+ SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000,
+
+ // This flag limits the complexity of an expression.
+ SH_LIMIT_EXPRESSION_COMPLEXITY = 0x2000,
+
+ // This flag limits the depth of the call stack.
+ SH_LIMIT_CALL_STACK_DEPTH = 0x4000,
+} ShCompileOptions;
+
+// Defines alternate strategies for implementing array index clamping.
+typedef enum {
+ // Use the clamp intrinsic for array index clamping.
+ SH_CLAMP_WITH_CLAMP_INTRINSIC = 1,
+
+ // Use a user-defined function for array index clamping.
+ SH_CLAMP_WITH_USER_DEFINED_INT_CLAMP_FUNCTION
+} ShArrayIndexClampingStrategy;
+
+//
+// Driver must call this first, once, before doing any other
+// compiler operations.
+// If the function succeeds, the return value is nonzero, else zero.
+//
+COMPILER_EXPORT int ShInitialize();
+//
+// Driver should call this at shutdown.
+// If the function succeeds, the return value is nonzero, else zero.
+//
+COMPILER_EXPORT int ShFinalize();
+
+// The 64 bits hash function. The first parameter is the input string; the
+// second parameter is the string length.
+typedef khronos_uint64_t (*ShHashFunction64)(const char*, size_t);
+
+//
+// Implementation dependent built-in resources (constants and extensions).
+// The names for these resources has been obtained by stripping gl_/GL_.
+//
+typedef struct
+{
+ // Constants.
+ int MaxVertexAttribs;
+ int MaxVertexUniformVectors;
+ int MaxVaryingVectors;
+ int MaxVertexTextureImageUnits;
+ int MaxCombinedTextureImageUnits;
+ int MaxTextureImageUnits;
+ int MaxFragmentUniformVectors;
+ int MaxDrawBuffers;
+
+ // Extensions.
+ // Set to 1 to enable the extension, else 0.
+ int OES_standard_derivatives;
+ int OES_EGL_image_external;
+ int ARB_texture_rectangle;
+ int EXT_draw_buffers;
+ int EXT_frag_depth;
+
+ // Set to 1 if highp precision is supported in the fragment language.
+ // Default is 0.
+ int FragmentPrecisionHigh;
+
+ // Name Hashing.
+ // Set a 64 bit hash function to enable user-defined name hashing.
+ // Default is NULL.
+ ShHashFunction64 HashFunction;
+
+ // Selects a strategy to use when implementing array index clamping.
+ // Default is SH_CLAMP_WITH_CLAMP_INTRINSIC.
+ ShArrayIndexClampingStrategy ArrayIndexClampingStrategy;
+
+ // The maximum complexity an expression can be.
+ int MaxExpressionComplexity;
+
+ // The maximum depth a call stack can be.
+ int MaxCallStackDepth;
+} ShBuiltInResources;
+
+//
+// Initialize built-in resources with minimum expected values.
+//
+COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources* resources);
+
+//
+// ShHandle held by but opaque to the driver. It is allocated,
+// managed, and de-allocated by the compiler. It's contents
+// are defined by and used by the compiler.
+//
+// If handle creation fails, 0 will be returned.
+//
+typedef void* ShHandle;
+
+//
+// Driver calls these to create and destroy compiler objects.
+//
+// Returns the handle of constructed compiler, null if the requested compiler is
+// not supported.
+// Parameters:
+// type: Specifies the type of shader - SH_FRAGMENT_SHADER or SH_VERTEX_SHADER.
+// spec: Specifies the language spec the compiler must conform to -
+// SH_GLES2_SPEC or SH_WEBGL_SPEC.
+// output: Specifies the output code type - SH_ESSL_OUTPUT, SH_GLSL_OUTPUT,
+// SH_HLSL9_OUTPUT or SH_HLSL11_OUTPUT.
+// resources: Specifies the built-in resources.
+COMPILER_EXPORT ShHandle ShConstructCompiler(
+ ShShaderType type,
+ ShShaderSpec spec,
+ ShShaderOutput output,
+ const ShBuiltInResources* resources);
+COMPILER_EXPORT void ShDestruct(ShHandle handle);
+
+//
+// Compiles the given shader source.
+// If the function succeeds, the return value is nonzero, else zero.
+// Parameters:
+// handle: Specifies the handle of compiler to be used.
+// shaderStrings: Specifies an array of pointers to null-terminated strings
+// containing the shader source code.
+// numStrings: Specifies the number of elements in shaderStrings array.
+// compileOptions: A mask containing the following parameters:
+// SH_VALIDATE: Validates shader to ensure that it conforms to the spec
+// specified during compiler construction.
+// SH_VALIDATE_LOOP_INDEXING: Validates loop and indexing in the shader to
+// ensure that they do not exceed the minimum
+// functionality mandated in GLSL 1.0 spec,
+// Appendix A, Section 4 and 5.
+// There is no need to specify this parameter when
+// compiling for WebGL - it is implied.
+// SH_INTERMEDIATE_TREE: Writes intermediate tree to info log.
+// Can be queried by calling ShGetInfoLog().
+// SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader.
+// Can be queried by calling ShGetObjectCode().
+// SH_ATTRIBUTES_UNIFORMS: Extracts attributes and uniforms.
+// Can be queried by calling ShGetActiveAttrib() and
+// ShGetActiveUniform().
+//
+COMPILER_EXPORT int ShCompile(
+ const ShHandle handle,
+ const char* const shaderStrings[],
+ size_t numStrings,
+ int compileOptions
+ );
+
+// Returns a parameter from a compiled shader.
+// Parameters:
+// handle: Specifies the compiler
+// pname: Specifies the parameter to query.
+// The following parameters are defined:
+// SH_INFO_LOG_LENGTH: the number of characters in the information log
+// including the null termination character.
+// SH_OBJECT_CODE_LENGTH: the number of characters in the object code
+// including the null termination character.
+// SH_ACTIVE_ATTRIBUTES: the number of active attribute variables.
+// SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: the length of the longest active attribute
+// variable name including the null
+// termination character.
+// SH_ACTIVE_UNIFORMS: the number of active uniform variables.
+// SH_ACTIVE_UNIFORM_MAX_LENGTH: the length of the longest active uniform
+// variable name including the null
+// termination character.
+// SH_MAPPED_NAME_MAX_LENGTH: the length of the mapped variable name including
+// the null termination character.
+// SH_NAME_MAX_LENGTH: the max length of a user-defined name including the
+// null termination character.
+// SH_HASHED_NAME_MAX_LENGTH: the max length of a hashed name including the
+// null termination character.
+// SH_HASHED_NAMES_COUNT: the number of hashed names from the latest compile.
+//
+// params: Requested parameter
+COMPILER_EXPORT void ShGetInfo(const ShHandle handle,
+ ShShaderInfo pname,
+ size_t* params);
+
+// Returns nul-terminated information log for a compiled shader.
+// Parameters:
+// handle: Specifies the compiler
+// infoLog: Specifies an array of characters that is used to return
+// the information log. It is assumed that infoLog has enough memory
+// to accomodate the information log. The size of the buffer required
+// to store the returned information log can be obtained by calling
+// ShGetInfo with SH_INFO_LOG_LENGTH.
+COMPILER_EXPORT void ShGetInfoLog(const ShHandle handle, char* infoLog);
+
+// Returns null-terminated object code for a compiled shader.
+// Parameters:
+// handle: Specifies the compiler
+// infoLog: Specifies an array of characters that is used to return
+// the object code. It is assumed that infoLog has enough memory to
+// accomodate the object code. The size of the buffer required to
+// store the returned object code can be obtained by calling
+// ShGetInfo with SH_OBJECT_CODE_LENGTH.
+COMPILER_EXPORT void ShGetObjectCode(const ShHandle handle, char* objCode);
+
+// Returns information about an active attribute variable.
+// Parameters:
+// handle: Specifies the compiler
+// index: Specifies the index of the attribute variable to be queried.
+// length: Returns the number of characters actually written in the string
+// indicated by name (excluding the null terminator) if a value other
+// than NULL is passed.
+// size: Returns the size of the attribute variable.
+// type: Returns the data type of the attribute variable.
+// name: Returns a null terminated string containing the name of the
+// attribute variable. It is assumed that name has enough memory to
+// accomodate the attribute variable name. The size of the buffer
+// required to store the attribute variable name can be obtained by
+// calling ShGetInfo with SH_ACTIVE_ATTRIBUTE_MAX_LENGTH.
+// mappedName: Returns a null terminated string containing the mapped name of
+// the attribute variable, It is assumed that mappedName has enough
+// memory (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care
+// about the mapped name. If the name is not mapped, then name and
+// mappedName are the same.
+COMPILER_EXPORT void ShGetActiveAttrib(const ShHandle handle,
+ int index,
+ size_t* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName);
+
+// Returns information about an active uniform variable.
+// Parameters:
+// handle: Specifies the compiler
+// index: Specifies the index of the uniform variable to be queried.
+// length: Returns the number of characters actually written in the string
+// indicated by name (excluding the null terminator) if a value
+// other than NULL is passed.
+// size: Returns the size of the uniform variable.
+// type: Returns the data type of the uniform variable.
+// name: Returns a null terminated string containing the name of the
+// uniform variable. It is assumed that name has enough memory to
+// accomodate the uniform variable name. The size of the buffer required
+// to store the uniform variable name can be obtained by calling
+// ShGetInfo with SH_ACTIVE_UNIFORMS_MAX_LENGTH.
+// mappedName: Returns a null terminated string containing the mapped name of
+// the uniform variable, It is assumed that mappedName has enough
+// memory (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care
+// about the mapped name. If the name is not mapped, then name and
+// mappedName are the same.
+COMPILER_EXPORT void ShGetActiveUniform(const ShHandle handle,
+ int index,
+ size_t* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName);
+
+// Returns information about a name hashing entry from the latest compile.
+// Parameters:
+// handle: Specifies the compiler
+// index: Specifies the index of the name hashing entry to be queried.
+// name: Returns a null terminated string containing the user defined name.
+// It is assumed that name has enough memory to accomodate the name.
+// The size of the buffer required to store the user defined name can
+// be obtained by calling ShGetInfo with SH_NAME_MAX_LENGTH.
+// hashedName: Returns a null terminated string containing the hashed name of
+// the uniform variable, It is assumed that hashedName has enough
+// memory to accomodate the name. The size of the buffer required
+// to store the name can be obtained by calling ShGetInfo with
+// SH_HASHED_NAME_MAX_LENGTH.
+COMPILER_EXPORT void ShGetNameHashingEntry(const ShHandle handle,
+ int index,
+ char* name,
+ char* hashedName);
+
+// Returns a parameter from a compiled shader.
+// Parameters:
+// handle: Specifies the compiler
+// pname: Specifies the parameter to query.
+// The following parameters are defined:
+// SH_ACTIVE_UNIFORMS_ARRAY: an STL vector of active uniforms. Valid only for
+// HLSL output.
+// params: Requested parameter
+COMPILER_EXPORT void ShGetInfoPointer(const ShHandle handle,
+ ShShaderInfo pname,
+ void** params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _COMPILER_INTERFACE_INCLUDED_
diff --git a/include/KHR/khrplatform.h b/include/KHR/khrplatform.h
new file mode 100644
index 00000000..8ec0d199
--- /dev/null
+++ b/include/KHR/khrplatform.h
@@ -0,0 +1,269 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by sending them to the public Khronos Bugzilla
+ * (http://khronos.org/bugzilla) by filing a bug against product
+ * "Khronos (general)" component "Registry".
+ *
+ * A predefined template which fills in some of the bug fields can be
+ * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+ * must create a Bugzilla login first.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ * http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ * #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ * khronos_int8_t signed 8 bit
+ * khronos_uint8_t unsigned 8 bit
+ * khronos_int16_t signed 16 bit
+ * khronos_uint16_t unsigned 16 bit
+ * khronos_int32_t signed 32 bit
+ * khronos_uint32_t unsigned 32 bit
+ * khronos_int64_t signed 64 bit
+ * khronos_uint64_t unsigned 64 bit
+ * khronos_intptr_t signed same number of bits as a pointer
+ * khronos_uintptr_t unsigned same number of bits as a pointer
+ * khronos_ssize_t signed size
+ * khronos_usize_t unsigned size
+ * khronos_float_t signed 32 bit floating point
+ * khronos_time_ns_t unsigned 64 bit time in nanoseconds
+ * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ * nanoseconds
+ * khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ * khronos_boolean_enum_t enumerated boolean type. This should
+ * only be used as a base type when a client API's boolean type is
+ * an enum. Client APIs which use an integer or other type for
+ * booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ * KHRONOS_APICALL
+ * KHRONOS_APIENTRY
+ * KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ * int arg1,
+ * int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
+# define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+# define KHRONOS_APICALL IMPORT_C
+#else
+# define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+ /* Win32 but not WinCE */
+# define KHRONOS_APIENTRY __stdcall
+#else
+# define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32 khronos_int32_t;
+typedef unsigned __int32 khronos_uint32_t;
+typedef __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int khronos_int64_t;
+typedef unsigned long int khronos_uint64_t;
+#else
+typedef long long int khronos_int64_t;
+typedef unsigned long long int khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64 0
+#define KHRONOS_SUPPORT_FLOAT 0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef float khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time. Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted). The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years. Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t khronos_utime_nanoseconds_t;
+typedef khronos_int64_t khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true. Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+ KHRONOS_FALSE = 0,
+ KHRONOS_TRUE = 1,
+ KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
diff --git a/samples/angle/Simple_Instancing/Simple_Instancing.c b/samples/angle/Simple_Instancing/Simple_Instancing.c
new file mode 100644
index 00000000..c513c9b3
--- /dev/null
+++ b/samples/angle/Simple_Instancing/Simple_Instancing.c
@@ -0,0 +1,230 @@
+//
+// Modified from Simple_Texture2D found in:
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// Simple_Instancing.c
+//
+// This is a simple example that draws two quads with a 2D
+// texture image. The purpose of this example is to demonstrate
+// the basics of ANGLE instancing in GLESv2.
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+#include <GLES2/gl2ext.h>
+
+PFNGLVERTEXATTRIBDIVISORANGLEPROC glVertexAttribDivisorANGLE;
+PFNGLDRAWARRAYSINSTANCEDANGLEPROC glDrawArraysInstancedANGLE;
+PFNGLDRAWELEMENTSINSTANCEDANGLEPROC glDrawElementsInstancedANGLE;
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+ GLint texCoordLoc;
+
+ // Sampler location
+ GLint samplerLoc;
+
+ // Texture handle
+ GLuint textureId;
+
+ // Instance VBO
+ GLint instancePosLoc;
+
+} UserData;
+
+///
+// Create a simple 2x2 texture image with four different colors
+//
+GLuint CreateSimpleTexture2D( )
+{
+ // Texture object handle
+ GLuint textureId;
+
+ // 2x2 Image, 3 bytes per pixel (R, G, B)
+ GLubyte pixels[4 * 3] =
+ {
+ 255, 0, 0, // Red
+ 0, 255, 0, // Green
+ 0, 0, 255, // Blue
+ 255, 255, 0 // Yellow
+ };
+
+ // Use tightly packed data
+ glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
+
+ // Generate a texture object
+ glGenTextures ( 1, &textureId );
+
+ // Bind the texture object
+ glBindTexture ( GL_TEXTURE_2D, textureId );
+
+ // Load the texture
+ glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+
+ // Set the filtering mode
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+
+ return textureId;
+
+}
+
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ // init instancing functions
+ char *extensionString = (char*) glGetString(GL_EXTENSIONS);
+
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "attribute vec3 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "attribute vec3 a_instancePos;\n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = vec4(a_position.xyz + a_instancePos.xyz, 1.0); \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+ "} \n";
+
+ if (strstr(extensionString, "GL_ANGLE_instanced_arrays"))
+ {
+ glVertexAttribDivisorANGLE = (PFNGLVERTEXATTRIBDIVISORANGLEPROC)eglGetProcAddress("glVertexAttribDivisorANGLE");
+ glDrawArraysInstancedANGLE = (PFNGLDRAWARRAYSINSTANCEDANGLEPROC)eglGetProcAddress("glDrawArraysInstancedANGLE");
+ glDrawElementsInstancedANGLE = (PFNGLDRAWELEMENTSINSTANCEDANGLEPROC)eglGetProcAddress("glDrawElementsInstancedANGLE");
+ }
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+ userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" );
+ userData->instancePosLoc = glGetAttribLocation ( userData->programObject, "a_instancePos" );
+
+ // Get the sampler location
+ userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
+
+ // Load the texture
+ userData->textureId = CreateSimpleTexture2D ();
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+ return TRUE;
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = (UserData*) esContext->userData;
+ GLfloat vVertices[] = { -0.2f, 0.2f, 0.0f, // Position 0
+ 0.0f, 0.0f, // TexCoord 0
+ -0.2f, -0.2f, 0.0f, // Position 1
+ 0.0f, 1.0f, // TexCoord 1
+ 0.2f, -0.2f, 0.0f, // Position 2
+ 1.0f, 1.0f, // TexCoord 2
+ 0.2f, 0.2f, 0.0f, // Position 3
+ 1.0f, 0.0f // TexCoord 3
+ };
+ GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+ GLfloat instanceVerts [] = { -0.3f, -0.3f, 0.0f, 0.3f, 0.3f, 0.0f };
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), vVertices );
+ // Load the texture coordinate
+ glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3] );
+
+ // Load the instance position
+ glVertexAttribPointer ( userData->instancePosLoc, 3, GL_FLOAT,
+ GL_FALSE, 3 * sizeof(GLfloat), instanceVerts );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+ glEnableVertexAttribArray ( userData->texCoordLoc );
+ glEnableVertexAttribArray ( userData->instancePosLoc );
+
+ // Enable instancing
+ glVertexAttribDivisorANGLE( userData->instancePosLoc, 1 );
+
+ // Bind the texture
+ glActiveTexture ( GL_TEXTURE0 );
+ glBindTexture ( GL_TEXTURE_2D, userData->textureId );
+
+ // Set the sampler texture unit to 0
+ glUniform1i ( userData->samplerLoc, 0 );
+
+ glDrawElementsInstancedANGLE ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices, 2 );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = (UserData*) esContext->userData;
+
+ // Delete texture object
+ glDeleteTextures ( 1, &userData->textureId );
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("Simple Instancing"), 320, 240, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/angle/Simple_Instancing/Simple_Instancing.vcxproj b/samples/angle/Simple_Instancing/Simple_Instancing.vcxproj
new file mode 100644
index 00000000..35ffe807
--- /dev/null
+++ b/samples/angle/Simple_Instancing/Simple_Instancing.vcxproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{EB6E138B-9DE5-41E8-A127-3675AA2BA607}</ProjectGuid>
+ <RootNamespace>Simple_Texture2D</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ <ProjectName>Simple_Instancing</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../../gles2_book/Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../../gles2_book/Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Simple_Instancing.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\gles2_book\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/build_samples.gyp b/samples/build_samples.gyp
new file mode 100644
index 00000000..a70eb049
--- /dev/null
+++ b/samples/build_samples.gyp
@@ -0,0 +1,178 @@
+# Copyright (c) 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'essl_to_glsl',
+ 'type': 'executable',
+ 'dependencies': [
+ '../src/build_angle.gyp:translator_glsl',
+ ],
+ 'include_dirs': [
+ '../include',
+ ],
+ 'sources': [
+ 'translator/translator.cpp',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'targets': [
+ {
+ 'target_name': 'essl_to_hlsl',
+ 'type': 'executable',
+ 'dependencies': [
+ '../src/build_angle.gyp:translator_hlsl',
+ ],
+ 'include_dirs': [
+ '../include',
+ '../src',
+ ],
+ 'sources': [
+ 'translator/translator.cpp',
+ '../src/common/debug.cpp',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': ['d3d9.lib'],
+ }
+ }
+ },
+ {
+ 'target_name': 'es_util',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../src/build_angle.gyp:libEGL',
+ '../src/build_angle.gyp:libGLESv2',
+ ],
+ 'include_dirs': [
+ 'gles2_book/Common',
+ '../include',
+ ],
+ 'sources': [
+ 'gles2_book/Common/esShader.c',
+ 'gles2_book/Common/esShapes.c',
+ 'gles2_book/Common/esTransform.c',
+ 'gles2_book/Common/esUtil.c',
+ 'gles2_book/Common/esUtil.h',
+ 'gles2_book/Common/esUtil_win.h',
+ 'gles2_book/Common/Win32/esUtil_TGA.c',
+ 'gles2_book/Common/Win32/esUtil_win32.c',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ 'gles2_book/Common',
+ '../include',
+ ],
+ },
+ },
+ {
+ 'target_name': 'hello_triangle',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/Hello_Triangle/Hello_Triangle.c',
+ ],
+ },
+ {
+ 'target_name': 'mip_map_2d',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/MipMap2D/MipMap2D.c',
+ ],
+ },
+ {
+ 'target_name': 'multi_texture',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/MultiTexture/MultiTexture.c',
+ ],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)',
+ 'files': [
+ 'gles2_book/MultiTexture/basemap.tga',
+ 'gles2_book/MultiTexture/lightmap.tga',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'particle_system',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/ParticleSystem/ParticleSystem.c',
+ ],
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)',
+ 'files': [
+ 'gles2_book/ParticleSystem/smoke.tga',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'simple_texture_2d',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/Simple_Texture2D/Simple_Texture2D.c',
+ ],
+ },
+ {
+ 'target_name': 'simple_texture_cubemap',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/Simple_TextureCubemap/Simple_TextureCubemap.c',
+ ],
+ },
+ {
+ 'target_name': 'simple_vertex_shader',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/Simple_VertexShader/Simple_VertexShader.c',
+ ],
+ },
+ {
+ 'target_name': 'stencil_test',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/Stencil_Test/Stencil_Test.c',
+ ],
+ },
+ {
+ 'target_name': 'texture_wrap',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/TextureWrap/TextureWrap.c',
+ ],
+ },
+ {
+ 'target_name': 'post_sub_buffer',
+ 'type': 'executable',
+ 'dependencies': ['es_util'],
+ 'sources': [
+ 'gles2_book/PostSubBuffer/PostSubBuffer.c',
+ ],
+ },
+ ],
+ }],
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/samples/gles2_book/Common/Win32/esUtil_TGA.c b/samples/gles2_book/Common/Win32/esUtil_TGA.c
new file mode 100644
index 00000000..61d1cb14
--- /dev/null
+++ b/samples/gles2_book/Common/Win32/esUtil_TGA.c
@@ -0,0 +1,122 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// esUtil_TGA.c
+//
+// This file contains the Win32 implementation of a TGA image loader
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+///
+// Macros
+//
+#define INVERTED_BIT (1 << 5)
+
+///
+// Types
+//
+#pragma pack(push,x1) // Byte alignment (8-bit)
+#pragma pack(1)
+
+typedef struct
+{
+ unsigned char IdSize,
+ MapType,
+ ImageType;
+ unsigned short PaletteStart,
+ PaletteSize;
+ unsigned char PaletteEntryDepth;
+ unsigned short X,
+ Y,
+ Width,
+ Height;
+ unsigned char ColorDepth,
+ Descriptor;
+
+} TGA_HEADER;
+
+#pragma pack(pop,x1)
+
+////////////////////////////////////////////////////////////////////////////////////
+//
+// Private Functions
+//
+
+////////////////////////////////////////////////////////////////////////////////////
+//
+// Public Functions
+//
+//
+
+
+///
+// WinTGALoad()
+//
+int WinTGALoad( const char *fileName, char **buffer, int *width, int *height )
+{
+ FILE *fp;
+ TGA_HEADER Header;
+
+ if ( fopen_s ( &fp, fileName, "rb" ) != 0 )
+ {
+ return FALSE;
+ }
+
+ if ( fp == NULL )
+ {
+ return FALSE;
+ }
+
+ fread ( &Header, sizeof(TGA_HEADER), 1, fp );
+
+ *width = Header.Width;
+ *height = Header.Height;
+
+ if ( Header.ColorDepth == 24 )
+ {
+ RGBTRIPLE *Buffer24;
+
+ Buffer24= (RGBTRIPLE*)malloc(sizeof(RGBTRIPLE) * (*width) * (*height));
+
+ if(Buffer24)
+ {
+ int i=0;
+ int x,
+ y;
+
+ fread(Buffer24, sizeof(RGBTRIPLE), (*width) * (*height), fp);
+
+ *buffer= (LPSTR) malloc(3 * (*width) * (*height));
+
+ for ( y = 0; y < *height; y++ )
+ for( x = 0; x < *width; x++ )
+ {
+ int Index= y * (*width) + x;
+
+ if(!(Header.Descriptor & INVERTED_BIT))
+ Index= ((*height) - 1 - y) * (*width) + x;
+
+ (*buffer)[(i * 3)]= Buffer24[Index].rgbtRed;
+ (*buffer)[(i * 3) + 1]= Buffer24[Index].rgbtGreen;
+ (*buffer)[(i * 3) + 2]= Buffer24[Index].rgbtBlue;
+
+ i++;
+ }
+
+ fclose(fp);
+ free(Buffer24);
+ return(TRUE);
+ }
+ }
+
+ return(FALSE);
+}
diff --git a/samples/gles2_book/Common/Win32/esUtil_win32.c b/samples/gles2_book/Common/Win32/esUtil_win32.c
new file mode 100644
index 00000000..c27131ed
--- /dev/null
+++ b/samples/gles2_book/Common/Win32/esUtil_win32.c
@@ -0,0 +1,190 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// esUtil_win32.c
+//
+// This file contains the Win32 implementation of the windowing functions.
+
+
+///
+// Includes
+//
+
+#include <windows.h>
+#include "esUtil.h"
+
+//////////////////////////////////////////////////////////////////
+//
+// Private Functions
+//
+//
+
+///
+// ESWindowProc()
+//
+// Main window procedure
+//
+LRESULT WINAPI ESWindowProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ LRESULT lRet = 1;
+
+ switch (uMsg)
+ {
+ case WM_CREATE:
+ break;
+
+ case WM_SIZE:
+ {
+ ESContext *esContext = (ESContext*)(LONG_PTR) GetWindowLongPtr ( hWnd, GWL_USERDATA );
+ if ( esContext ) {
+ esContext->width = LOWORD( lParam );
+ esContext->height = HIWORD( lParam );
+ InvalidateRect( esContext->hWnd, NULL, FALSE );
+ }
+ }
+
+ case WM_PAINT:
+ {
+ ESContext *esContext = (ESContext*)(LONG_PTR) GetWindowLongPtr ( hWnd, GWL_USERDATA );
+
+ if ( esContext && esContext->drawFunc )
+ esContext->drawFunc ( esContext );
+
+ if ( esContext )
+ ValidateRect( esContext->hWnd, NULL );
+ }
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ case WM_CHAR:
+ {
+ POINT point;
+ ESContext *esContext = (ESContext*)(LONG_PTR) GetWindowLongPtr ( hWnd, GWL_USERDATA );
+
+ GetCursorPos( &point );
+
+ if ( esContext && esContext->keyFunc )
+ esContext->keyFunc ( esContext, (unsigned char) wParam,
+ (int) point.x, (int) point.y );
+}
+ break;
+
+ default:
+ lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
+ break;
+ }
+
+ return lRet;
+}
+
+//////////////////////////////////////////////////////////////////
+//
+// Public Functions
+//
+//
+
+///
+// WinCreate()
+//
+// Create Win32 instance and window
+//
+GLboolean WinCreate ( ESContext *esContext, LPCTSTR title )
+{
+ WNDCLASS wndclass = {0};
+ DWORD wStyle = 0;
+ RECT windowRect;
+ HINSTANCE hInstance = GetModuleHandle(NULL);
+
+ wndclass.style = CS_OWNDC;
+ wndclass.lpfnWndProc = (WNDPROC)ESWindowProc;
+ wndclass.hInstance = hInstance;
+ wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ wndclass.lpszClassName = TEXT("opengles2.0");
+
+ if (!RegisterClass (&wndclass) )
+ return FALSE;
+
+ wStyle = WS_VISIBLE | WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_SIZEBOX;
+
+ // Adjust the window rectangle so that the client area has
+ // the correct number of pixels
+ windowRect.left = 0;
+ windowRect.top = 0;
+ windowRect.right = esContext->width;
+ windowRect.bottom = esContext->height;
+
+ AdjustWindowRect ( &windowRect, wStyle, FALSE );
+
+ esContext->hWnd = CreateWindow(
+ TEXT("opengles2.0"),
+ title,
+ wStyle,
+ 0,
+ 0,
+ windowRect.right - windowRect.left,
+ windowRect.bottom - windowRect.top,
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ // Set the ESContext* to the GWL_USERDATA so that it is available to the
+ // ESWindowProc
+ SetWindowLongPtr ( esContext->hWnd, GWL_USERDATA, (LONG) (LONG_PTR) esContext );
+
+ if ( esContext->hWnd == NULL )
+ return GL_FALSE;
+
+ ShowWindow ( esContext->hWnd, TRUE );
+
+ return GL_TRUE;
+}
+
+///
+// winLoop()
+//
+// Start main windows loop
+//
+void WinLoop ( ESContext *esContext )
+{
+ MSG msg = { 0 };
+ int done = 0;
+ DWORD lastTime = GetTickCount();
+
+ while (!done)
+ {
+ int gotMsg = (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0);
+ DWORD curTime = GetTickCount();
+ float deltaTime = (float)( curTime - lastTime ) / 1000.0f;
+ lastTime = curTime;
+
+ if ( gotMsg )
+ {
+ if (msg.message==WM_QUIT)
+ {
+ done=1;
+ }
+ else
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ else
+ SendMessage( esContext->hWnd, WM_PAINT, 0, 0 );
+
+ // Call update function if registered
+ if ( esContext->updateFunc != NULL )
+ esContext->updateFunc ( esContext, deltaTime );
+ }
+}
diff --git a/samples/gles2_book/Common/esShader.c b/samples/gles2_book/Common/esShader.c
new file mode 100644
index 00000000..a2bb6e52
--- /dev/null
+++ b/samples/gles2_book/Common/esShader.c
@@ -0,0 +1,155 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// ESShader.c
+//
+// Utility functions for loading shaders and creating program objects.
+//
+
+///
+// Includes
+//
+#include "esUtil.h"
+#include <stdlib.h>
+
+//////////////////////////////////////////////////////////////////
+//
+// Private Functions
+//
+//
+
+
+
+//////////////////////////////////////////////////////////////////
+//
+// Public Functions
+//
+//
+
+//
+///
+/// \brief Load a shader, check for compile errors, print error messages to output log
+/// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER)
+/// \param shaderSrc Shader source string
+/// \return A new shader object on success, 0 on failure
+//
+GLuint ESUTIL_API esLoadShader ( GLenum type, const char *shaderSrc )
+{
+ GLuint shader;
+ GLint compiled;
+
+ // Create the shader object
+ shader = glCreateShader ( type );
+
+ if ( shader == 0 )
+ return 0;
+
+ // Load the shader source
+ glShaderSource ( shader, 1, &shaderSrc, NULL );
+
+ // Compile the shader
+ glCompileShader ( shader );
+
+ // Check the compile status
+ glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );
+
+ if ( !compiled )
+ {
+ GLint infoLen = 0;
+
+ glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
+
+ if ( infoLen > 1 )
+ {
+ char* infoLog = malloc (sizeof(char) * infoLen );
+
+ glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
+ esLogMessage ( "Error compiling shader:\n%s\n", infoLog );
+
+ free ( infoLog );
+ }
+
+ glDeleteShader ( shader );
+ return 0;
+ }
+
+ return shader;
+
+}
+
+
+//
+///
+/// \brief Load a vertex and fragment shader, create a program object, link program.
+// Errors output to log.
+/// \param vertShaderSrc Vertex shader source code
+/// \param fragShaderSrc Fragment shader source code
+/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
+//
+GLuint ESUTIL_API esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc )
+{
+ GLuint vertexShader;
+ GLuint fragmentShader;
+ GLuint programObject;
+ GLint linked;
+
+ // Load the vertex/fragment shaders
+ vertexShader = esLoadShader ( GL_VERTEX_SHADER, vertShaderSrc );
+ if ( vertexShader == 0 )
+ return 0;
+
+ fragmentShader = esLoadShader ( GL_FRAGMENT_SHADER, fragShaderSrc );
+ if ( fragmentShader == 0 )
+ {
+ glDeleteShader( vertexShader );
+ return 0;
+ }
+
+ // Create the program object
+ programObject = glCreateProgram ( );
+
+ if ( programObject == 0 )
+ return 0;
+
+ glAttachShader ( programObject, vertexShader );
+ glAttachShader ( programObject, fragmentShader );
+
+ // Link the program
+ glLinkProgram ( programObject );
+
+ // Check the link status
+ glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
+
+ if ( !linked )
+ {
+ GLint infoLen = 0;
+
+ glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );
+
+ if ( infoLen > 1 )
+ {
+ char* infoLog = malloc (sizeof(char) * infoLen );
+
+ glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
+ esLogMessage ( "Error linking program:\n%s\n", infoLog );
+
+ free ( infoLog );
+ }
+
+ glDeleteProgram ( programObject );
+ return 0;
+ }
+
+ // Free up no longer needed shader resources
+ glDeleteShader ( vertexShader );
+ glDeleteShader ( fragmentShader );
+
+ return programObject;
+}
diff --git a/samples/gles2_book/Common/esShapes.c b/samples/gles2_book/Common/esShapes.c
new file mode 100644
index 00000000..6813534e
--- /dev/null
+++ b/samples/gles2_book/Common/esShapes.c
@@ -0,0 +1,279 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// ESShapes.c
+//
+// Utility functions for generating shapes
+//
+
+///
+// Includes
+//
+#include "esUtil.h"
+#include <stdlib.h>
+#include <math.h>
+
+///
+// Defines
+//
+#define ES_PI (3.14159265f)
+
+//////////////////////////////////////////////////////////////////
+//
+// Private Functions
+//
+//
+
+
+
+//////////////////////////////////////////////////////////////////
+//
+// Public Functions
+//
+//
+
+//
+/// \brief Generates geometry for a sphere. Allocates memory for the vertex data and stores
+/// the results in the arrays. Generate index list for a TRIANGLE_STRIP
+/// \param numSlices The number of slices in the sphere
+/// \param vertices If not NULL, will contain array of float3 positions
+/// \param normals If not NULL, will contain array of float3 normals
+/// \param texCoords If not NULL, will contain array of float2 texCoords
+/// \param indices If not NULL, will contain the array of indices for the triangle strip
+/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
+/// if it is not NULL ) as a GL_TRIANGLE_STRIP
+//
+int ESUTIL_API esGenSphere ( int numSlices, float radius, GLfloat **vertices, GLfloat **normals,
+ GLfloat **texCoords, GLushort **indices )
+{
+ int i;
+ int j;
+ int numParallels = numSlices / 2;
+ int numVertices = ( numParallels + 1 ) * ( numSlices + 1 );
+ int numIndices = numParallels * numSlices * 6;
+ float angleStep = (2.0f * ES_PI) / ((float) numSlices);
+
+ // Allocate memory for buffers
+ if ( vertices != NULL )
+ *vertices = malloc ( sizeof(GLfloat) * 3 * numVertices );
+
+ if ( normals != NULL )
+ *normals = malloc ( sizeof(GLfloat) * 3 * numVertices );
+
+ if ( texCoords != NULL )
+ *texCoords = malloc ( sizeof(GLfloat) * 2 * numVertices );
+
+ if ( indices != NULL )
+ *indices = malloc ( sizeof(GLushort) * numIndices );
+
+ for ( i = 0; i < numParallels + 1; i++ )
+ {
+ for ( j = 0; j < numSlices + 1; j++ )
+ {
+ int vertex = ( i * (numSlices + 1) + j ) * 3;
+
+ if ( vertices )
+ {
+ (*vertices)[vertex + 0] = radius * sinf ( angleStep * (float)i ) *
+ sinf ( angleStep * (float)j );
+ (*vertices)[vertex + 1] = radius * cosf ( angleStep * (float)i );
+ (*vertices)[vertex + 2] = radius * sinf ( angleStep * (float)i ) *
+ cosf ( angleStep * (float)j );
+ }
+
+ if ( normals )
+ {
+ (*normals)[vertex + 0] = (*vertices)[vertex + 0] / radius;
+ (*normals)[vertex + 1] = (*vertices)[vertex + 1] / radius;
+ (*normals)[vertex + 2] = (*vertices)[vertex + 2] / radius;
+ }
+
+ if ( texCoords )
+ {
+ int texIndex = ( i * (numSlices + 1) + j ) * 2;
+ (*texCoords)[texIndex + 0] = (float) j / (float) numSlices;
+ (*texCoords)[texIndex + 1] = ( 1.0f - (float) i ) / (float) (numParallels - 1 );
+ }
+ }
+ }
+
+ // Generate the indices
+ if ( indices != NULL )
+ {
+ GLushort *indexBuf = (*indices);
+ for ( i = 0; i < numParallels ; i++ )
+ {
+ for ( j = 0; j < numSlices; j++ )
+ {
+ *indexBuf++ = i * ( numSlices + 1 ) + j;
+ *indexBuf++ = ( i + 1 ) * ( numSlices + 1 ) + j;
+ *indexBuf++ = ( i + 1 ) * ( numSlices + 1 ) + ( j + 1 );
+
+ *indexBuf++ = i * ( numSlices + 1 ) + j;
+ *indexBuf++ = ( i + 1 ) * ( numSlices + 1 ) + ( j + 1 );
+ *indexBuf++ = i * ( numSlices + 1 ) + ( j + 1 );
+ }
+ }
+ }
+
+ return numIndices;
+}
+
+//
+/// \brief Generates geometry for a cube. Allocates memory for the vertex data and stores
+/// the results in the arrays. Generate index list for a TRIANGLES
+/// \param scale The size of the cube, use 1.0 for a unit cube.
+/// \param vertices If not NULL, will contain array of float3 positions
+/// \param normals If not NULL, will contain array of float3 normals
+/// \param texCoords If not NULL, will contain array of float2 texCoords
+/// \param indices If not NULL, will contain the array of indices for the triangle strip
+/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
+/// if it is not NULL ) as a GL_TRIANGLE_STRIP
+//
+int ESUTIL_API esGenCube ( float scale, GLfloat **vertices, GLfloat **normals,
+ GLfloat **texCoords, GLushort **indices )
+{
+ int i;
+ int numVertices = 24;
+ int numIndices = 36;
+
+ GLfloat cubeVerts[] =
+ {
+ -0.5f, -0.5f, -0.5f,
+ -0.5f, -0.5f, 0.5f,
+ 0.5f, -0.5f, 0.5f,
+ 0.5f, -0.5f, -0.5f,
+ -0.5f, 0.5f, -0.5f,
+ -0.5f, 0.5f, 0.5f,
+ 0.5f, 0.5f, 0.5f,
+ 0.5f, 0.5f, -0.5f,
+ -0.5f, -0.5f, -0.5f,
+ -0.5f, 0.5f, -0.5f,
+ 0.5f, 0.5f, -0.5f,
+ 0.5f, -0.5f, -0.5f,
+ -0.5f, -0.5f, 0.5f,
+ -0.5f, 0.5f, 0.5f,
+ 0.5f, 0.5f, 0.5f,
+ 0.5f, -0.5f, 0.5f,
+ -0.5f, -0.5f, -0.5f,
+ -0.5f, -0.5f, 0.5f,
+ -0.5f, 0.5f, 0.5f,
+ -0.5f, 0.5f, -0.5f,
+ 0.5f, -0.5f, -0.5f,
+ 0.5f, -0.5f, 0.5f,
+ 0.5f, 0.5f, 0.5f,
+ 0.5f, 0.5f, -0.5f,
+ };
+
+ GLfloat cubeNormals[] =
+ {
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 0.0f, 1.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ };
+
+ GLfloat cubeTex[] =
+ {
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+ 1.0f, 0.0f,
+ 1.0f, 1.0f,
+ 0.0f, 1.0f,
+ 0.0f, 0.0f,
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f,
+ };
+
+ // Allocate memory for buffers
+ if ( vertices != NULL )
+ {
+ *vertices = malloc ( sizeof(GLfloat) * 3 * numVertices );
+ memcpy( *vertices, cubeVerts, sizeof( cubeVerts ) );
+ for ( i = 0; i < numVertices; i++ )
+ {
+ (*vertices)[i] *= scale;
+ }
+ }
+
+ if ( normals != NULL )
+ {
+ *normals = malloc ( sizeof(GLfloat) * 3 * numVertices );
+ memcpy( *normals, cubeNormals, sizeof( cubeNormals ) );
+ }
+
+ if ( texCoords != NULL )
+ {
+ *texCoords = malloc ( sizeof(GLfloat) * 2 * numVertices );
+ memcpy( *texCoords, cubeTex, sizeof( cubeTex ) ) ;
+ }
+
+
+ // Generate the indices
+ if ( indices != NULL )
+ {
+ GLushort cubeIndices[] =
+ {
+ 0, 2, 1,
+ 0, 3, 2,
+ 4, 5, 6,
+ 4, 6, 7,
+ 8, 9, 10,
+ 8, 10, 11,
+ 12, 15, 14,
+ 12, 14, 13,
+ 16, 17, 18,
+ 16, 18, 19,
+ 20, 23, 22,
+ 20, 22, 21
+ };
+
+ *indices = malloc ( sizeof(GLushort) * numIndices );
+ memcpy( *indices, cubeIndices, sizeof( cubeIndices ) );
+ }
+
+ return numIndices;
+}
diff --git a/samples/gles2_book/Common/esTransform.c b/samples/gles2_book/Common/esTransform.c
new file mode 100644
index 00000000..7da8f765
--- /dev/null
+++ b/samples/gles2_book/Common/esTransform.c
@@ -0,0 +1,212 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// ESUtil.c
+//
+// A utility library for OpenGL ES. This library provides a
+// basic common framework for the example applications in the
+// OpenGL ES 2.0 Programming Guide.
+//
+
+///
+// Includes
+//
+#include "esUtil.h"
+#include <math.h>
+
+#define PI 3.1415926535897932384626433832795f
+
+void ESUTIL_API
+esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz)
+{
+ result->m[0][0] *= sx;
+ result->m[0][1] *= sx;
+ result->m[0][2] *= sx;
+ result->m[0][3] *= sx;
+
+ result->m[1][0] *= sy;
+ result->m[1][1] *= sy;
+ result->m[1][2] *= sy;
+ result->m[1][3] *= sy;
+
+ result->m[2][0] *= sz;
+ result->m[2][1] *= sz;
+ result->m[2][2] *= sz;
+ result->m[2][3] *= sz;
+}
+
+void ESUTIL_API
+esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz)
+{
+ result->m[3][0] += (result->m[0][0] * tx + result->m[1][0] * ty + result->m[2][0] * tz);
+ result->m[3][1] += (result->m[0][1] * tx + result->m[1][1] * ty + result->m[2][1] * tz);
+ result->m[3][2] += (result->m[0][2] * tx + result->m[1][2] * ty + result->m[2][2] * tz);
+ result->m[3][3] += (result->m[0][3] * tx + result->m[1][3] * ty + result->m[2][3] * tz);
+}
+
+void ESUTIL_API
+esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+{
+ GLfloat sinAngle, cosAngle;
+ GLfloat mag = sqrtf(x * x + y * y + z * z);
+
+ sinAngle = sinf ( angle * PI / 180.0f );
+ cosAngle = cosf ( angle * PI / 180.0f );
+ if ( mag > 0.0f )
+ {
+ GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs;
+ GLfloat oneMinusCos;
+ ESMatrix rotMat;
+
+ x /= mag;
+ y /= mag;
+ z /= mag;
+
+ xx = x * x;
+ yy = y * y;
+ zz = z * z;
+ xy = x * y;
+ yz = y * z;
+ zx = z * x;
+ xs = x * sinAngle;
+ ys = y * sinAngle;
+ zs = z * sinAngle;
+ oneMinusCos = 1.0f - cosAngle;
+
+ rotMat.m[0][0] = (oneMinusCos * xx) + cosAngle;
+ rotMat.m[0][1] = (oneMinusCos * xy) - zs;
+ rotMat.m[0][2] = (oneMinusCos * zx) + ys;
+ rotMat.m[0][3] = 0.0F;
+
+ rotMat.m[1][0] = (oneMinusCos * xy) + zs;
+ rotMat.m[1][1] = (oneMinusCos * yy) + cosAngle;
+ rotMat.m[1][2] = (oneMinusCos * yz) - xs;
+ rotMat.m[1][3] = 0.0F;
+
+ rotMat.m[2][0] = (oneMinusCos * zx) - ys;
+ rotMat.m[2][1] = (oneMinusCos * yz) + xs;
+ rotMat.m[2][2] = (oneMinusCos * zz) + cosAngle;
+ rotMat.m[2][3] = 0.0F;
+
+ rotMat.m[3][0] = 0.0F;
+ rotMat.m[3][1] = 0.0F;
+ rotMat.m[3][2] = 0.0F;
+ rotMat.m[3][3] = 1.0F;
+
+ esMatrixMultiply( result, &rotMat, result );
+ }
+}
+
+void ESUTIL_API
+esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ)
+{
+ float deltaX = right - left;
+ float deltaY = top - bottom;
+ float deltaZ = farZ - nearZ;
+ ESMatrix frust;
+
+ if ( (nearZ <= 0.0f) || (farZ <= 0.0f) ||
+ (deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f) )
+ return;
+
+ frust.m[0][0] = 2.0f * nearZ / deltaX;
+ frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f;
+
+ frust.m[1][1] = 2.0f * nearZ / deltaY;
+ frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f;
+
+ frust.m[2][0] = (right + left) / deltaX;
+ frust.m[2][1] = (top + bottom) / deltaY;
+ frust.m[2][2] = -(nearZ + farZ) / deltaZ;
+ frust.m[2][3] = -1.0f;
+
+ frust.m[3][2] = -2.0f * nearZ * farZ / deltaZ;
+ frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f;
+
+ esMatrixMultiply(result, &frust, result);
+}
+
+
+void ESUTIL_API
+esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ)
+{
+ GLfloat frustumW, frustumH;
+
+ frustumH = tanf( fovy / 360.0f * PI ) * nearZ;
+ frustumW = frustumH * aspect;
+
+ esFrustum( result, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ );
+}
+
+void ESUTIL_API
+esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ)
+{
+ float deltaX = right - left;
+ float deltaY = top - bottom;
+ float deltaZ = farZ - nearZ;
+ ESMatrix ortho;
+
+ if ( (deltaX == 0.0f) || (deltaY == 0.0f) || (deltaZ == 0.0f) )
+ return;
+
+ esMatrixLoadIdentity(&ortho);
+ ortho.m[0][0] = 2.0f / deltaX;
+ ortho.m[3][0] = -(right + left) / deltaX;
+ ortho.m[1][1] = 2.0f / deltaY;
+ ortho.m[3][1] = -(top + bottom) / deltaY;
+ ortho.m[2][2] = -2.0f / deltaZ;
+ ortho.m[3][2] = -(nearZ + farZ) / deltaZ;
+
+ esMatrixMultiply(result, &ortho, result);
+}
+
+
+void ESUTIL_API
+esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB)
+{
+ ESMatrix tmp = { 0.0f };
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ tmp.m[i][0] = (srcA->m[i][0] * srcB->m[0][0]) +
+ (srcA->m[i][1] * srcB->m[1][0]) +
+ (srcA->m[i][2] * srcB->m[2][0]) +
+ (srcA->m[i][3] * srcB->m[3][0]) ;
+
+ tmp.m[i][1] = (srcA->m[i][0] * srcB->m[0][1]) +
+ (srcA->m[i][1] * srcB->m[1][1]) +
+ (srcA->m[i][2] * srcB->m[2][1]) +
+ (srcA->m[i][3] * srcB->m[3][1]) ;
+
+ tmp.m[i][2] = (srcA->m[i][0] * srcB->m[0][2]) +
+ (srcA->m[i][1] * srcB->m[1][2]) +
+ (srcA->m[i][2] * srcB->m[2][2]) +
+ (srcA->m[i][3] * srcB->m[3][2]) ;
+
+ tmp.m[i][3] = (srcA->m[i][0] * srcB->m[0][3]) +
+ (srcA->m[i][1] * srcB->m[1][3]) +
+ (srcA->m[i][2] * srcB->m[2][3]) +
+ (srcA->m[i][3] * srcB->m[3][3]) ;
+ }
+ memcpy(result, &tmp, sizeof(ESMatrix));
+}
+
+
+void ESUTIL_API
+esMatrixLoadIdentity(ESMatrix *result)
+{
+ memset(result, 0x0, sizeof(ESMatrix));
+ result->m[0][0] = 1.0f;
+ result->m[1][1] = 1.0f;
+ result->m[2][2] = 1.0f;
+ result->m[3][3] = 1.0f;
+}
+
diff --git a/samples/gles2_book/Common/esUtil.c b/samples/gles2_book/Common/esUtil.c
new file mode 100644
index 00000000..aeeee7ff
--- /dev/null
+++ b/samples/gles2_book/Common/esUtil.c
@@ -0,0 +1,290 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// ESUtil.c
+//
+// A utility library for OpenGL ES. This library provides a
+// basic common framework for the example applications in the
+// OpenGL ES 2.0 Programming Guide.
+//
+
+///
+// Includes
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include "esUtil.h"
+#include "esUtil_win.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4204) // nonstandard extension used : non-constant aggregate initializer
+#endif
+
+///
+// Extensions
+//
+
+PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
+PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
+
+PFNEGLPOSTSUBBUFFERNVPROC eglPostSubBufferNV;
+
+PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
+
+PFNGLDELETEFENCESNVPROC glDeleteFencesNV;
+PFNGLGENFENCESNVPROC glGenFencesNV;
+PFNGLGETFENCEIVNVPROC glGetFenceivNV;
+PFNGLISFENCENVPROC glIsFenceNV;
+PFNGLFINISHFENCENVPROC glFinishFenceNV;
+PFNGLSETFENCENVPROC glSetFenceNV;
+PFNGLTESTFENCENVPROC glTestFenceNV;
+
+///
+// CreateEGLContext()
+//
+// Creates an EGL rendering context and all associated elements
+//
+EGLBoolean CreateEGLContext ( EGLNativeWindowType hWnd, EGLDisplay* eglDisplay,
+ EGLContext* eglContext, EGLSurface* eglSurface,
+ EGLint* configAttribList, EGLint* surfaceAttribList)
+{
+ EGLint numConfigs;
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLDisplay display;
+ EGLContext context;
+ EGLSurface surface;
+ EGLConfig config;
+ EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
+
+ // Get Display
+ display = eglGetDisplay(GetDC(hWnd));
+ if ( display == EGL_NO_DISPLAY )
+ {
+ return EGL_FALSE;
+ }
+
+ // Initialize EGL
+ if ( !eglInitialize(display, &majorVersion, &minorVersion) )
+ {
+ return EGL_FALSE;
+ }
+
+ // Bind to extensions
+ eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
+ eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
+
+ eglPostSubBufferNV = (PFNEGLPOSTSUBBUFFERNVPROC) eglGetProcAddress("eglPostSubBufferNV");
+
+ glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES");
+
+ glDeleteFencesNV = (PFNGLDELETEFENCESNVPROC) eglGetProcAddress("glDeleteFencesNV");
+ glGenFencesNV = (PFNGLGENFENCESNVPROC) eglGetProcAddress("glGenFencesNV");
+ glGetFenceivNV = (PFNGLGETFENCEIVNVPROC) eglGetProcAddress("glGetFenceivNV");
+ glIsFenceNV = (PFNGLISFENCENVPROC) eglGetProcAddress("glIsFenceNV");
+ glFinishFenceNV = (PFNGLFINISHFENCENVPROC) eglGetProcAddress("glFinishFenceNV");
+ glSetFenceNV = (PFNGLSETFENCENVPROC) eglGetProcAddress("glSetFenceNV");
+ glTestFenceNV = (PFNGLTESTFENCENVPROC) eglGetProcAddress("glTestFenceNV");
+
+ // Get configs
+ if ( !eglGetConfigs(display, NULL, 0, &numConfigs) )
+ {
+ return EGL_FALSE;
+ }
+
+ // Choose config
+ if ( !eglChooseConfig(display, configAttribList, &config, 1, &numConfigs) )
+ {
+ return EGL_FALSE;
+ }
+
+ // Create a surface
+ surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)hWnd, surfaceAttribList);
+ if ( surface == EGL_NO_SURFACE )
+ {
+ return EGL_FALSE;
+ }
+
+ // Create a GL context
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs );
+ if ( context == EGL_NO_CONTEXT )
+ {
+ return EGL_FALSE;
+ }
+
+ // Make the context current
+ if ( !eglMakeCurrent(display, surface, surface, context) )
+ {
+ return EGL_FALSE;
+ }
+
+ *eglDisplay = display;
+ *eglSurface = surface;
+ *eglContext = context;
+ return EGL_TRUE;
+}
+
+//////////////////////////////////////////////////////////////////
+//
+// Public Functions
+//
+//
+
+///
+// esInitContext()
+//
+// Initialize ES utility context. This must be called before calling any other
+// functions.
+//
+void ESUTIL_API esInitContext ( ESContext *esContext )
+{
+ if ( esContext != NULL )
+ {
+ memset( esContext, 0, sizeof( ESContext) );
+ }
+}
+
+///
+// esCreateWindow()
+//
+// title - name for title bar of window
+// width - width of window to create
+// height - height of window to create
+// flags - bitwise or of window creation flags
+// ES_WINDOW_ALPHA - specifies that the framebuffer should have alpha
+// ES_WINDOW_DEPTH - specifies that a depth buffer should be created
+// ES_WINDOW_STENCIL - specifies that a stencil buffer should be created
+// ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created
+// ES_WINDOW_POST_SUB_BUFFER_SUPPORTED - specifies that EGL_POST_SUB_BUFFER_NV is supported.
+//
+GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, LPCTSTR title, GLint width, GLint height, GLuint flags )
+{
+ EGLint configAttribList[] =
+ {
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_ALPHA_SIZE, (flags & ES_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,
+ EGL_DEPTH_SIZE, (flags & ES_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,
+ EGL_STENCIL_SIZE, (flags & ES_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,
+ EGL_SAMPLE_BUFFERS, (flags & ES_WINDOW_MULTISAMPLE) ? 1 : 0,
+ EGL_NONE
+ };
+ EGLint surfaceAttribList[] =
+ {
+ EGL_POST_SUB_BUFFER_SUPPORTED_NV, flags & (ES_WINDOW_POST_SUB_BUFFER_SUPPORTED) ? EGL_TRUE : EGL_FALSE,
+ EGL_NONE, EGL_NONE
+ };
+
+ if ( esContext == NULL )
+ {
+ return GL_FALSE;
+ }
+
+ esContext->width = width;
+ esContext->height = height;
+
+ if ( !WinCreate ( esContext, title) )
+ {
+ return GL_FALSE;
+ }
+
+
+ if ( !CreateEGLContext ( esContext->hWnd,
+ &esContext->eglDisplay,
+ &esContext->eglContext,
+ &esContext->eglSurface,
+ configAttribList,
+ surfaceAttribList ) )
+ {
+ return GL_FALSE;
+ }
+
+
+ return GL_TRUE;
+}
+
+///
+// esMainLoop()
+//
+// Start the main loop for the OpenGL ES application
+//
+void ESUTIL_API esMainLoop ( ESContext *esContext )
+{
+ WinLoop ( esContext );
+}
+
+
+///
+// esRegisterDrawFunc()
+//
+void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) (ESContext* ) )
+{
+ esContext->drawFunc = drawFunc;
+}
+
+
+///
+// esRegisterUpdateFunc()
+//
+void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) )
+{
+ esContext->updateFunc = updateFunc;
+}
+
+
+///
+// esRegisterKeyFunc()
+//
+void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext,
+ void (ESCALLBACK *keyFunc) (ESContext*, unsigned char, int, int ) )
+{
+ esContext->keyFunc = keyFunc;
+}
+
+
+///
+// esLogMessage()
+//
+// Log an error message to the debug output for the platform
+//
+void ESUTIL_API esLogMessage ( const char *formatStr, ... )
+{
+ va_list params;
+ char buf[BUFSIZ];
+
+ va_start ( params, formatStr );
+ vsprintf_s ( buf, sizeof(buf), formatStr, params );
+
+ printf ( "%s", buf );
+
+ va_end ( params );
+}
+
+
+///
+// esLoadTGA()
+//
+// Loads a 24-bit TGA image from a file
+//
+char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height )
+{
+ char *buffer;
+
+ if ( WinTGALoad ( fileName, &buffer, width, height ) )
+ {
+ return buffer;
+ }
+
+ return NULL;
+}
diff --git a/samples/gles2_book/Common/esUtil.h b/samples/gles2_book/Common/esUtil.h
new file mode 100644
index 00000000..7b7595c0
--- /dev/null
+++ b/samples/gles2_book/Common/esUtil.h
@@ -0,0 +1,297 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+//
+/// \file ESUtil.h
+/// \brief A utility library for OpenGL ES. This library provides a
+/// basic common framework for the example applications in the
+/// OpenGL ES 2.0 Programming Guide.
+//
+#ifndef ESUTIL_H
+#define ESUTIL_H
+
+///
+// Includes
+//
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#ifdef __cplusplus
+
+extern "C" {
+#endif
+
+
+///
+// Macros
+//
+#define ESUTIL_API __cdecl
+#define ESCALLBACK __cdecl
+
+
+/// esCreateWindow flag - RGB color buffer
+#define ES_WINDOW_RGB 0
+/// esCreateWindow flag - ALPHA color buffer
+#define ES_WINDOW_ALPHA 1
+/// esCreateWindow flag - depth buffer
+#define ES_WINDOW_DEPTH 2
+/// esCreateWindow flag - stencil buffer
+#define ES_WINDOW_STENCIL 4
+/// esCreateWindow flag - multi-sample buffer
+#define ES_WINDOW_MULTISAMPLE 8
+/// esCreateWindow flag - EGL_POST_SUB_BUFFER_NV supported.
+#define ES_WINDOW_POST_SUB_BUFFER_SUPPORTED 16
+
+///
+// Types
+//
+
+typedef struct
+{
+ GLfloat m[4][4];
+} ESMatrix;
+
+typedef struct
+{
+ /// Put your user data here...
+ void* userData;
+
+ /// Window width
+ GLint width;
+
+ /// Window height
+ GLint height;
+
+ /// Window handle
+ EGLNativeWindowType hWnd;
+
+ /// EGL display
+ EGLDisplay eglDisplay;
+
+ /// EGL context
+ EGLContext eglContext;
+
+ /// EGL surface
+ EGLSurface eglSurface;
+
+ /// Callbacks
+ void (ESCALLBACK *drawFunc) ( void* );
+ void (ESCALLBACK *keyFunc) ( void*, unsigned char, int, int );
+ void (ESCALLBACK *updateFunc) ( void*, float deltaTime );
+} ESContext;
+
+
+///
+// Extensions
+//
+
+extern PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
+extern PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
+
+extern PFNEGLPOSTSUBBUFFERNVPROC eglPostSubBufferNV;
+
+extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
+
+extern PFNGLDELETEFENCESNVPROC glDeleteFencesNV;
+extern PFNGLGENFENCESNVPROC glGenFencesNV;
+extern PFNGLGETFENCEIVNVPROC glGetFenceivNV;
+extern PFNGLISFENCENVPROC glIsFenceNV;
+extern PFNGLFINISHFENCENVPROC glFinishFenceNV;
+extern PFNGLSETFENCENVPROC glSetFenceNV;
+extern PFNGLTESTFENCENVPROC glTestFenceNV;
+
+///
+// Public Functions
+//
+
+//
+///
+/// \brief Initialize ES framework context. This must be called before calling any other functions.
+/// \param esContext Application context
+//
+void ESUTIL_API esInitContext ( ESContext *esContext );
+
+//
+/// \brief Create a window with the specified parameters
+/// \param esContext Application context
+/// \param title Name for title bar of window
+/// \param width Width in pixels of window to create
+/// \param height Height in pixels of window to create
+/// \param flags Bitfield for the window creation flags
+/// ES_WINDOW_RGB - specifies that the color buffer should have R,G,B channels
+/// ES_WINDOW_ALPHA - specifies that the color buffer should have alpha
+/// ES_WINDOW_DEPTH - specifies that a depth buffer should be created
+/// ES_WINDOW_STENCIL - specifies that a stencil buffer should be created
+/// ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created
+/// ES_WINDOW_POST_SUB_BUFFER_SUPPORTED - specifies that EGL_POST_SUB_BUFFER_NV is supported.
+/// \return GL_TRUE if window creation is succesful, GL_FALSE otherwise
+GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, LPCTSTR title, GLint width, GLint height, GLuint flags );
+
+//
+/// \brief Start the main loop for the OpenGL ES application
+/// \param esContext Application context
+//
+void ESUTIL_API esMainLoop ( ESContext *esContext );
+
+//
+/// \brief Register a draw callback function to be used to render each frame
+/// \param esContext Application context
+/// \param drawFunc Draw callback function that will be used to render the scene
+//
+void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) ( ESContext* ) );
+
+//
+/// \brief Register an update callback function to be used to update on each time step
+/// \param esContext Application context
+/// \param updateFunc Update callback function that will be used to render the scene
+//
+void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) );
+
+//
+/// \brief Register an keyboard input processing callback function
+/// \param esContext Application context
+/// \param keyFunc Key callback function for application processing of keyboard input
+//
+void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext,
+ void (ESCALLBACK *drawFunc) ( ESContext*, unsigned char, int, int ) );
+//
+/// \brief Log a message to the debug output for the platform
+/// \param formatStr Format string for error log.
+//
+void ESUTIL_API esLogMessage ( const char *formatStr, ... );
+
+//
+///
+/// \brief Load a shader, check for compile errors, print error messages to output log
+/// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER)
+/// \param shaderSrc Shader source string
+/// \return A new shader object on success, 0 on failure
+//
+GLuint ESUTIL_API esLoadShader ( GLenum type, const char *shaderSrc );
+
+//
+///
+/// \brief Load a vertex and fragment shader, create a program object, link program.
+/// Errors output to log.
+/// \param vertShaderSrc Vertex shader source code
+/// \param fragShaderSrc Fragment shader source code
+/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
+//
+GLuint ESUTIL_API esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc );
+
+
+//
+/// \brief Generates geometry for a sphere. Allocates memory for the vertex data and stores
+/// the results in the arrays. Generate index list for a TRIANGLE_STRIP
+/// \param numSlices The number of slices in the sphere
+/// \param vertices If not NULL, will contain array of float3 positions
+/// \param normals If not NULL, will contain array of float3 normals
+/// \param texCoords If not NULL, will contain array of float2 texCoords
+/// \param indices If not NULL, will contain the array of indices for the triangle strip
+/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
+/// if it is not NULL ) as a GL_TRIANGLE_STRIP
+//
+int ESUTIL_API esGenSphere ( int numSlices, float radius, GLfloat **vertices, GLfloat **normals,
+ GLfloat **texCoords, GLushort **indices );
+
+//
+/// \brief Generates geometry for a cube. Allocates memory for the vertex data and stores
+/// the results in the arrays. Generate index list for a TRIANGLES
+/// \param scale The size of the cube, use 1.0 for a unit cube.
+/// \param vertices If not NULL, will contain array of float3 positions
+/// \param normals If not NULL, will contain array of float3 normals
+/// \param texCoords If not NULL, will contain array of float2 texCoords
+/// \param indices If not NULL, will contain the array of indices for the triangle strip
+/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
+/// if it is not NULL ) as a GL_TRIANGLES
+//
+int ESUTIL_API esGenCube ( float scale, GLfloat **vertices, GLfloat **normals,
+ GLfloat **texCoords, GLushort **indices );
+
+//
+/// \brief Loads a 24-bit TGA image from a file
+/// \param fileName Name of the file on disk
+/// \param width Width of loaded image in pixels
+/// \param height Height of loaded image in pixels
+/// \return Pointer to loaded image. NULL on failure.
+//
+char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height );
+
+
+//
+/// \brief multiply matrix specified by result with a scaling matrix and return new matrix in result
+/// \param result Specifies the input matrix. Scaled matrix is returned in result.
+/// \param sx, sy, sz Scale factors along the x, y and z axes respectively
+//
+void ESUTIL_API esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz);
+
+//
+/// \brief multiply matrix specified by result with a translation matrix and return new matrix in result
+/// \param result Specifies the input matrix. Translated matrix is returned in result.
+/// \param tx, ty, tz Scale factors along the x, y and z axes respectively
+//
+void ESUTIL_API esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz);
+
+//
+/// \brief multiply matrix specified by result with a rotation matrix and return new matrix in result
+/// \param result Specifies the input matrix. Rotated matrix is returned in result.
+/// \param angle Specifies the angle of rotation, in degrees.
+/// \param x, y, z Specify the x, y and z coordinates of a vector, respectively
+//
+void ESUTIL_API esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+
+//
+// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
+/// \param result Specifies the input matrix. new matrix is returned in result.
+/// \param left, right Coordinates for the left and right vertical clipping planes
+/// \param bottom, top Coordinates for the bottom and top horizontal clipping planes
+/// \param nearZ, farZ Distances to the near and far depth clipping planes. Both distances must be positive.
+//
+void ESUTIL_API esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
+
+//
+/// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
+/// \param result Specifies the input matrix. new matrix is returned in result.
+/// \param fovy Field of view y angle in degrees
+/// \param aspect Aspect ratio of screen
+/// \param nearZ Near plane distance
+/// \param farZ Far plane distance
+//
+void ESUTIL_API esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ);
+
+//
+/// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
+/// \param result Specifies the input matrix. new matrix is returned in result.
+/// \param left, right Coordinates for the left and right vertical clipping planes
+/// \param bottom, top Coordinates for the bottom and top horizontal clipping planes
+/// \param nearZ, farZ Distances to the near and far depth clipping planes. These values are negative if plane is behind the viewer
+//
+void ESUTIL_API esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
+
+//
+/// \brief perform the following operation - result matrix = srcA matrix * srcB matrix
+/// \param result Returns multiplied matrix
+/// \param srcA, srcB Input matrices to be multiplied
+//
+void ESUTIL_API esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB);
+
+//
+//// \brief return an indentity matrix
+//// \param result returns identity matrix
+//
+void ESUTIL_API esMatrixLoadIdentity(ESMatrix *result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ESUTIL_H
diff --git a/samples/gles2_book/Common/esUtil.vcxproj b/samples/gles2_book/Common/esUtil.vcxproj
new file mode 100644
index 00000000..8619f2c3
--- /dev/null
+++ b/samples/gles2_book/Common/esUtil.vcxproj
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{47C93F52-AB4E-4FF9-8D4F-B38CD60A183F}</ProjectGuid>
+ <RootNamespace>esUtil</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>./;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>./;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Win32\esUtil_TGA.c" />
+ <ClCompile Include="Win32\esUtil_win32.c" />
+ <ClCompile Include="esShader.c" />
+ <ClCompile Include="esShapes.c" />
+ <ClCompile Include="esTransform.c" />
+ <ClCompile Include="esUtil.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="esUtil_win.h" />
+ <ClInclude Include="esUtil.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\src\libEGL\libEGL.vcxproj">
+ <Project>{e746fca9-64c3-433e-85e8-9a5a67ab7ed6}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <Private>true</Private>
+ <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\src\libGLESv2\libGLESv2.vcxproj">
+ <Project>{b5871a7a-968c-42e3-a33b-981e6f448e78}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <Private>true</Private>
+ <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/Common/esUtil.vcxproj.filters b/samples/gles2_book/Common/esUtil.vcxproj.filters
new file mode 100644
index 00000000..b2eb5846
--- /dev/null
+++ b/samples/gles2_book/Common/esUtil.vcxproj.filters
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Win32">
+ <UniqueIdentifier>{8b3de51d-fe0c-4a62-aa51-feb196406ff8}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Common">
+ <UniqueIdentifier>{cdf112d8-e32a-47f8-8095-2b433bc4fc0f}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Win32\esUtil_TGA.c">
+ <Filter>Win32</Filter>
+ </ClCompile>
+ <ClCompile Include="Win32\esUtil_win32.c">
+ <Filter>Win32</Filter>
+ </ClCompile>
+ <ClCompile Include="esShader.c">
+ <Filter>Common</Filter>
+ </ClCompile>
+ <ClCompile Include="esShapes.c">
+ <Filter>Common</Filter>
+ </ClCompile>
+ <ClCompile Include="esTransform.c">
+ <Filter>Common</Filter>
+ </ClCompile>
+ <ClCompile Include="esUtil.c">
+ <Filter>Common</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="esUtil_win.h">
+ <Filter>Win32</Filter>
+ </ClInclude>
+ <ClInclude Include="esUtil.h">
+ <Filter>Common</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/Common/esUtil_win.h b/samples/gles2_book/Common/esUtil_win.h
new file mode 100644
index 00000000..8ba34069
--- /dev/null
+++ b/samples/gles2_book/Common/esUtil_win.h
@@ -0,0 +1,65 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// esUtil_win.h
+//
+// API-neutral interface for creating windows. Implementation needs to be provided per-platform.
+
+#ifndef ESUTIL_WIN_H
+#define ESUTIL_WIN_H
+
+///
+// Includes
+//
+
+#ifdef __cplusplus
+
+extern "C" {
+#endif
+
+
+///
+// Macros
+//
+
+///
+// Types
+//
+
+///
+// Public Functions
+//
+
+///
+// WinCreate()
+//
+// Create Win32 instance and window
+//
+GLboolean WinCreate ( ESContext *esContext, LPCTSTR title );
+
+///
+// WinLoop()
+//
+// Start main windows loop
+//
+void WinLoop ( ESContext *esContext );
+
+///
+// WinTGALoad()
+//
+// TGA loader win32 implementation
+//
+int WinTGALoad ( const char *fileName, char **buffer, int *width, int *height );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ESUTIL_WIN_H
diff --git a/samples/gles2_book/Hello_Triangle/Hello_Triangle.c b/samples/gles2_book/Hello_Triangle/Hello_Triangle.c
new file mode 100644
index 00000000..b0e3a4c8
--- /dev/null
+++ b/samples/gles2_book/Hello_Triangle/Hello_Triangle.c
@@ -0,0 +1,194 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// Hello_Triangle.c
+//
+// This is a simple example that draws a single triangle with
+// a minimal vertex/fragment shader. The purpose of this
+// example is to demonstrate the basic concepts of
+// OpenGL ES 2.0 rendering.
+#include <stdlib.h>
+#include "esUtil.h"
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+} UserData;
+
+///
+// Create a shader object, load the shader source, and
+// compile the shader.
+//
+GLuint LoadShader ( GLenum type, const char *shaderSrc )
+{
+ GLuint shader;
+ GLint compiled;
+
+ // Create the shader object
+ shader = glCreateShader ( type );
+
+ if ( shader == 0 )
+ return 0;
+
+ // Load the shader source
+ glShaderSource ( shader, 1, &shaderSrc, NULL );
+
+ // Compile the shader
+ glCompileShader ( shader );
+
+ // Check the compile status
+ glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );
+
+ if ( !compiled )
+ {
+ GLint infoLen = 0;
+
+ glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
+
+ if ( infoLen > 1 )
+ {
+ char* infoLog = malloc (sizeof(char) * infoLen );
+
+ glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
+ esLogMessage ( "Error compiling shader:\n%s\n", infoLog );
+
+ free ( infoLog );
+ }
+
+ glDeleteShader ( shader );
+ return 0;
+ }
+
+ return shader;
+
+}
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "attribute vec4 vPosition; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = vPosition; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float;\n"\
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );\n"
+ "} \n";
+
+ GLuint vertexShader;
+ GLuint fragmentShader;
+ GLuint programObject;
+ GLint linked;
+
+ // Load the vertex/fragment shaders
+ vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
+ fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );
+
+ // Create the program object
+ programObject = glCreateProgram ( );
+
+ if ( programObject == 0 )
+ return 0;
+
+ glAttachShader ( programObject, vertexShader );
+ glAttachShader ( programObject, fragmentShader );
+
+ // Bind vPosition to attribute 0
+ glBindAttribLocation ( programObject, 0, "vPosition" );
+
+ // Link the program
+ glLinkProgram ( programObject );
+
+ // Check the link status
+ glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
+
+ if ( !linked )
+ {
+ GLint infoLen = 0;
+
+ glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );
+
+ if ( infoLen > 1 )
+ {
+ char* infoLog = malloc (sizeof(char) * infoLen );
+
+ glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
+ esLogMessage ( "Error linking program:\n%s\n", infoLog );
+
+ free ( infoLog );
+ }
+
+ glDeleteProgram ( programObject );
+ return FALSE;
+ }
+
+ // Store the program object
+ userData->programObject = programObject;
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+ return TRUE;
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f,
+ -0.5f, -0.5f, 0.0f,
+ 0.5f, -0.5f, 0.0f };
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex data
+ glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
+ glEnableVertexAttribArray ( 0 );
+
+ glDrawArrays ( GL_TRIANGLES, 0, 3 );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("Hello Triangle"), 320, 240, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+
+ esMainLoop ( &esContext );
+}
diff --git a/samples/gles2_book/Hello_Triangle/Hello_Triangle.vcxproj b/samples/gles2_book/Hello_Triangle/Hello_Triangle.vcxproj
new file mode 100644
index 00000000..2267d937
--- /dev/null
+++ b/samples/gles2_book/Hello_Triangle/Hello_Triangle.vcxproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{8278251F-6C1F-4D80-8499-FA7B590FAFE6}</ProjectGuid>
+ <RootNamespace>Hello_Triangle</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Hello_Triangle.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/MipMap2D/MipMap2D.c b/samples/gles2_book/MipMap2D/MipMap2D.c
new file mode 100644
index 00000000..bc70cd4c
--- /dev/null
+++ b/samples/gles2_book/MipMap2D/MipMap2D.c
@@ -0,0 +1,346 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// MipMap2D.c
+//
+// This is a simple example that demonstrates generating a mipmap chain
+// and rendering with it
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+ GLint texCoordLoc;
+
+ // Sampler location
+ GLint samplerLoc;
+
+ // Offset location
+ GLint offsetLoc;
+
+ // Texture handle
+ GLuint textureId;
+
+} UserData;
+
+
+///
+// From an RGB8 source image, generate the next level mipmap
+//
+GLboolean GenMipMap2D( GLubyte *src, GLubyte **dst, int srcWidth, int srcHeight, int *dstWidth, int *dstHeight )
+{
+ int x,
+ y;
+ int texelSize = 3;
+
+ *dstWidth = srcWidth / 2;
+ if ( *dstWidth <= 0 )
+ *dstWidth = 1;
+
+ *dstHeight = srcHeight / 2;
+ if ( *dstHeight <= 0 )
+ *dstHeight = 1;
+
+ *dst = malloc ( sizeof(GLubyte) * texelSize * (*dstWidth) * (*dstHeight) );
+ if ( *dst == NULL )
+ return GL_FALSE;
+
+ for ( y = 0; y < *dstHeight; y++ )
+ {
+ for( x = 0; x < *dstWidth; x++ )
+ {
+ int srcIndex[4];
+ float r = 0.0f,
+ g = 0.0f,
+ b = 0.0f;
+ int sample;
+
+ // Compute the offsets for 2x2 grid of pixels in previous
+ // image to perform box filter
+ srcIndex[0] =
+ (((y * 2) * srcWidth) + (x * 2)) * texelSize;
+ srcIndex[1] =
+ (((y * 2) * srcWidth) + (x * 2 + 1)) * texelSize;
+ srcIndex[2] =
+ ((((y * 2) + 1) * srcWidth) + (x * 2)) * texelSize;
+ srcIndex[3] =
+ ((((y * 2) + 1) * srcWidth) + (x * 2 + 1)) * texelSize;
+
+ // Sum all pixels
+ for ( sample = 0; sample < 4; sample++ )
+ {
+ r += src[srcIndex[sample]];
+ g += src[srcIndex[sample] + 1];
+ b += src[srcIndex[sample] + 2];
+ }
+
+ // Average results
+ r /= 4.0;
+ g /= 4.0;
+ b /= 4.0;
+
+ // Store resulting pixels
+ (*dst)[ ( y * (*dstWidth) + x ) * texelSize ] = (GLubyte)( r );
+ (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 1] = (GLubyte)( g );
+ (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 2] = (GLubyte)( b );
+ }
+ }
+
+ return GL_TRUE;
+}
+
+///
+// Generate an RGB8 checkerboard image
+//
+GLubyte* GenCheckImage( int width, int height, int checkSize )
+{
+ int x,
+ y;
+ GLubyte *pixels = malloc( width * height * 3 );
+
+ if ( pixels == NULL )
+ return NULL;
+
+ for ( y = 0; y < height; y++ )
+ for ( x = 0; x < width; x++ )
+ {
+ GLubyte rColor = 0;
+ GLubyte bColor = 0;
+
+ if ( ( x / checkSize ) % 2 == 0 )
+ {
+ rColor = 255 * ( ( y / checkSize ) % 2 );
+ bColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) );
+ }
+ else
+ {
+ bColor = 255 * ( ( y / checkSize ) % 2 );
+ rColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) );
+ }
+
+ pixels[(y * height + x) * 3] = rColor;
+ pixels[(y * height + x) * 3 + 1] = 0;
+ pixels[(y * height + x) * 3 + 2] = bColor;
+ }
+
+ return pixels;
+}
+
+///
+// Create a mipmapped 2D texture image
+//
+GLuint CreateMipMappedTexture2D( )
+{
+ // Texture object handle
+ GLuint textureId;
+ int width = 256,
+ height = 256;
+ int level;
+ GLubyte *pixels;
+ GLubyte *prevImage;
+ GLubyte *newImage = NULL;
+
+ pixels = GenCheckImage( width, height, 8 );
+ if ( pixels == NULL )
+ return 0;
+
+ // Generate a texture object
+ glGenTextures ( 1, &textureId );
+
+ // Bind the texture object
+ glBindTexture ( GL_TEXTURE_2D, textureId );
+
+ // Load mipmap level 0
+ glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height,
+ 0, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+
+ level = 1;
+ prevImage = &pixels[0];
+
+ while ( width > 1 && height > 1 )
+ {
+ int newWidth,
+ newHeight;
+
+ // Generate the next mipmap level
+ GenMipMap2D( prevImage, &newImage, width, height,
+ &newWidth, &newHeight );
+
+ // Load the mipmap level
+ glTexImage2D( GL_TEXTURE_2D, level, GL_RGB,
+ newWidth, newHeight, 0, GL_RGB,
+ GL_UNSIGNED_BYTE, newImage );
+
+ // Free the previous image
+ free ( prevImage );
+
+ // Set the previous image for the next iteration
+ prevImage = newImage;
+ level++;
+
+ // Half the width and height
+ width = newWidth;
+ height = newHeight;
+ }
+
+ free ( newImage );
+
+ // Set the filtering mode
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+ return textureId;
+
+}
+
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "uniform float u_offset; \n"
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = a_position; \n"
+ " gl_Position.x += u_offset;\n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+ "} \n";
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+ userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" );
+
+ // Get the sampler location
+ userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
+
+ // Get the offset location
+ userData->offsetLoc = glGetUniformLocation( userData->programObject, "u_offset" );
+
+ // Load the texture
+ userData->textureId = CreateMipMappedTexture2D ();
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+ return TRUE;
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLfloat vVertices[] = { -0.5f, 0.5f, 0.0f, 1.5f, // Position 0
+ 0.0f, 0.0f, // TexCoord 0
+ -0.5f, -0.5f, 0.0f, 0.75f, // Position 1
+ 0.0f, 1.0f, // TexCoord 1
+ 0.5f, -0.5f, 0.0f, 0.75f, // Position 2
+ 1.0f, 1.0f, // TexCoord 2
+ 0.5f, 0.5f, 0.0f, 1.5f, // Position 3
+ 1.0f, 0.0f // TexCoord 3
+ };
+ GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 4, GL_FLOAT,
+ GL_FALSE, 6 * sizeof(GLfloat), vVertices );
+ // Load the texture coordinate
+ glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT,
+ GL_FALSE, 6 * sizeof(GLfloat), &vVertices[4] );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+ glEnableVertexAttribArray ( userData->texCoordLoc );
+
+ // Bind the texture
+ glActiveTexture ( GL_TEXTURE0 );
+ glBindTexture ( GL_TEXTURE_2D, userData->textureId );
+
+ // Set the sampler texture unit to 0
+ glUniform1i ( userData->samplerLoc, 0 );
+
+ // Draw quad with nearest sampling
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glUniform1f ( userData->offsetLoc, -0.6f );
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ // Draw quad with trilinear filtering
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+ glUniform1f ( userData->offsetLoc, 0.6f );
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Delete texture object
+ glDeleteTextures ( 1, &userData->textureId );
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("MipMap 2D"), 320, 240, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/MipMap2D/MipMap2D.vcxproj b/samples/gles2_book/MipMap2D/MipMap2D.vcxproj
new file mode 100644
index 00000000..bc9dc4d1
--- /dev/null
+++ b/samples/gles2_book/MipMap2D/MipMap2D.vcxproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{4E69AC1F-1C7A-4D58-917C-E764FBEB489A}</ProjectGuid>
+ <RootNamespace>MipMap2D</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="MipMap2D.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/MultiTexture/MultiTexture.c b/samples/gles2_book/MultiTexture/MultiTexture.c
new file mode 100644
index 00000000..bb2224a3
--- /dev/null
+++ b/samples/gles2_book/MultiTexture/MultiTexture.c
@@ -0,0 +1,213 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// MultiTexture.c
+//
+// This is an example that draws a quad with a basemap and
+// lightmap to demonstrate multitexturing.
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+ GLint texCoordLoc;
+
+ // Sampler locations
+ GLint baseMapLoc;
+ GLint lightMapLoc;
+
+ // Texture handle
+ GLuint baseMapTexId;
+ GLuint lightMapTexId;
+
+} UserData;
+
+
+///
+// Load texture from disk
+//
+GLuint LoadTexture ( char *fileName )
+{
+ int width,
+ height;
+ char *buffer = esLoadTGA ( fileName, &width, &height );
+ GLuint texId;
+
+ if ( buffer == NULL )
+ {
+ esLogMessage ( "Error loading (%s) image.\n", fileName );
+ return 0;
+ }
+
+ glGenTextures ( 1, &texId );
+ glBindTexture ( GL_TEXTURE_2D, texId );
+
+ glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+
+ free ( buffer );
+
+ return texId;
+}
+
+
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = a_position; \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_baseMap; \n"
+ "uniform sampler2D s_lightMap; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 baseColor; \n"
+ " vec4 lightColor; \n"
+ " \n"
+ " baseColor = texture2D( s_baseMap, v_texCoord ); \n"
+ " lightColor = texture2D( s_lightMap, v_texCoord ); \n"
+ " gl_FragColor = baseColor * (lightColor + 0.25); \n"
+ "} \n";
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+ userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" );
+
+ // Get the sampler location
+ userData->baseMapLoc = glGetUniformLocation ( userData->programObject, "s_baseMap" );
+ userData->lightMapLoc = glGetUniformLocation ( userData->programObject, "s_lightMap" );
+
+ // Load the textures
+ userData->baseMapTexId = LoadTexture ( "basemap.tga" );
+ userData->lightMapTexId = LoadTexture ( "lightmap.tga" );
+
+ if ( userData->baseMapTexId == 0 || userData->lightMapTexId == 0 )
+ return FALSE;
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+ return TRUE;
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLfloat vVertices[] = { -0.5f, 0.5f, 0.0f, // Position 0
+ 0.0f, 0.0f, // TexCoord 0
+ -0.5f, -0.5f, 0.0f, // Position 1
+ 0.0f, 1.0f, // TexCoord 1
+ 0.5f, -0.5f, 0.0f, // Position 2
+ 1.0f, 1.0f, // TexCoord 2
+ 0.5f, 0.5f, 0.0f, // Position 3
+ 1.0f, 0.0f // TexCoord 3
+ };
+ GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), vVertices );
+ // Load the texture coordinate
+ glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3] );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+ glEnableVertexAttribArray ( userData->texCoordLoc );
+
+ // Bind the base map
+ glActiveTexture ( GL_TEXTURE0 );
+ glBindTexture ( GL_TEXTURE_2D, userData->baseMapTexId );
+
+ // Set the base map sampler to texture unit to 0
+ glUniform1i ( userData->baseMapLoc, 0 );
+
+ // Bind the light map
+ glActiveTexture ( GL_TEXTURE1 );
+ glBindTexture ( GL_TEXTURE_2D, userData->lightMapTexId );
+
+ // Set the light map sampler to texture unit 1
+ glUniform1i ( userData->lightMapLoc, 1 );
+
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Delete texture object
+ glDeleteTextures ( 1, &userData->baseMapTexId );
+ glDeleteTextures ( 1, &userData->lightMapTexId );
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("MultiTexture"), 320, 240, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/MultiTexture/MultiTexture.vcxproj b/samples/gles2_book/MultiTexture/MultiTexture.vcxproj
new file mode 100644
index 00000000..b0ee09c8
--- /dev/null
+++ b/samples/gles2_book/MultiTexture/MultiTexture.vcxproj
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{120CFF94-ED4B-4C5B-9587-9E40889F15F7}</ProjectGuid>
+ <RootNamespace>MultiTexture</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /D /Y basemap.tga "$(OutDir)"
+xcopy /D /Y lightmap.tga "$(OutDir)"
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /D /Y basemap.tga "$(OutDir)"
+xcopy /D /Y lightmap.tga "$(OutDir)"
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="MultiTexture.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/MultiTexture/basemap.tga b/samples/gles2_book/MultiTexture/basemap.tga
new file mode 100644
index 00000000..8acafae2
--- /dev/null
+++ b/samples/gles2_book/MultiTexture/basemap.tga
Binary files differ
diff --git a/samples/gles2_book/MultiTexture/lightmap.tga b/samples/gles2_book/MultiTexture/lightmap.tga
new file mode 100644
index 00000000..d95b2628
--- /dev/null
+++ b/samples/gles2_book/MultiTexture/lightmap.tga
Binary files differ
diff --git a/samples/gles2_book/MultipleRenderTargets/MultipleRenderTargets.c b/samples/gles2_book/MultipleRenderTargets/MultipleRenderTargets.c
new file mode 100644
index 00000000..0e06c29f
--- /dev/null
+++ b/samples/gles2_book/MultipleRenderTargets/MultipleRenderTargets.c
@@ -0,0 +1,295 @@
+//
+// Modified from Simple_Texture2D, found in:
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// MultipleRenderTargets.c
+//
+// This is a simple example that shows how to use multiple render
+// targets in GLES 2.0 using EXT_draw_buffers. The example
+// draws to three render targets and displays
+// them together in a final pass.
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+PFNGLDRAWBUFFERSEXTPROC glDrawBuffersEXT;
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObjectMRT;
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+ GLint texCoordLoc;
+
+ // Sampler location
+ GLint samplerLoc;
+
+ // Texture handle
+ GLuint textureId;
+
+ // Framebuffer object handle
+ GLuint framebuffer;
+
+ // Framebuffer color attachments
+ GLuint framebufferTextures[4];
+
+} UserData;
+
+///
+// Create a simple 2x2 texture image with four different colors
+//
+GLuint CreateSimpleTexture2D( )
+{
+ // Texture object handle
+ GLuint textureId;
+
+ // 2x2 Image, 3 bytes per pixel (R, G, B)
+ GLubyte pixels[4 * 3] =
+ {
+ 255, 0, 0, // Red
+ 0, 255, 0, // Green
+ 0, 0, 255, // Blue
+ 255, 255, 0 // Yellow
+ };
+
+ // Use tightly packed data
+ glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
+
+ // Generate a texture object
+ glGenTextures ( 1, &textureId );
+
+ // Bind the texture object
+ glBindTexture ( GL_TEXTURE_2D, textureId );
+
+ // Load the texture
+ glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+
+ // Set the filtering mode
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+
+ return textureId;
+
+}
+
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = (UserData*)esContext->userData;
+ GLbyte vShaderStr[] =
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = a_position; \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+
+ GLbyte fMultiShaderStr[] =
+ "#extension GL_EXT_draw_buffers : enable \n"
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 color = texture2D( s_texture, v_texCoord ); \n"
+ " gl_FragData[0] = color; \n"
+ " gl_FragData[1] = vec4(1.0, 1.0, 1.0, 1.0) - color.brga;\n"
+ " gl_FragData[2] = vec4(0.2, 1.0, 0.5, 1.0) * color.gbra;\n"
+ " gl_FragData[3] = color.rrra; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 color = texture2D( s_texture, v_texCoord ); \n"
+ " gl_FragColor = color; \n"
+ "} \n";
+
+ int i;
+
+ // Check EXT_draw_buffers is supported
+ if (strstr(glGetString(GL_EXTENSIONS), "GL_EXT_draw_buffers") == 0)
+ {
+ return FALSE;
+ }
+
+ // Retrieve the address of glDrawBuffersEXT from EGL
+ glDrawBuffersEXT = (PFNGLDRAWBUFFERSEXTPROC)eglGetProcAddress("glDrawBuffersEXT");
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( (const char*)vShaderStr, (const char*)fShaderStr );
+
+ userData->programObjectMRT = esLoadProgram ( (const char*)vShaderStr, (const char*)fMultiShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+ userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" );
+
+ // Get the sampler location
+ userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
+
+ // Load the texture
+ userData->textureId = CreateSimpleTexture2D ();
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+
+ // Initialize the user framebuffer
+ glGenFramebuffers(1, &userData->framebuffer);
+ glGenTextures(4, userData->framebufferTextures);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, userData->framebuffer);
+
+ for (i = 0; i < 4; i++)
+ {
+ // Create textures for the four color attachments
+ glBindTexture(GL_TEXTURE_2D, userData->framebufferTextures[i]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, esContext->width, esContext->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_2D, userData->framebufferTextures[i], 0);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ return TRUE;
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = (UserData*)esContext->userData;
+ GLfloat vVertices[] = { -0.8f, 0.8f, 0.0f, // Position 0
+ 0.0f, 0.0f, // TexCoord 0
+ -0.8f, -0.8f, 0.0f, // Position 1
+ 0.0f, 1.0f, // TexCoord 1
+ 0.8f, -0.8f, 0.0f, // Position 2
+ 1.0f, 1.0f, // TexCoord 2
+ 0.8f, 0.8f, 0.0f, // Position 3
+ 1.0f, 0.0f // TexCoord 3
+ };
+ GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+ GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_COLOR_ATTACHMENT3_EXT };
+
+ // Enable drawing to the four color attachments of the user framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, userData->framebuffer);
+ glDrawBuffersEXT(4, drawBuffers);
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObjectMRT );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), vVertices );
+ // Load the texture coordinate
+ glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3] );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+ glEnableVertexAttribArray ( userData->texCoordLoc );
+
+ // Bind the texture
+ glActiveTexture ( GL_TEXTURE0 );
+ glBindTexture ( GL_TEXTURE_2D, userData->textureId );
+
+ // Set the sampler texture unit to 0
+ glUniform1i ( userData->samplerLoc, 0 );
+
+ // Draw the textured quad to the four render targets
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ // Enable the default framebuffer and single textured drawing
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glUseProgram ( userData->programObject );
+
+ // Draw the four textured quads to a separate region in the viewport
+ glBindTexture( GL_TEXTURE_2D, userData->framebufferTextures[0]);
+ glViewport ( 0, 0, esContext->width/2, esContext->height/2 );
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ glBindTexture( GL_TEXTURE_2D, userData->framebufferTextures[1]);
+ glViewport ( esContext->width/2, 0, esContext->width/2, esContext->height/2 );
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ glBindTexture( GL_TEXTURE_2D, userData->framebufferTextures[2]);
+ glViewport ( 0, esContext->height/2, esContext->width/2, esContext->height/2 );
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ glBindTexture( GL_TEXTURE_2D, userData->framebufferTextures[3]);
+ glViewport ( esContext->width/2, esContext->height/2, esContext->width/2, esContext->height/2 );
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = (UserData*)esContext->userData;
+
+ glDeleteTextures(4, userData->framebufferTextures);
+
+ glDeleteFramebuffers(1, &userData->framebuffer);
+
+ // Delete texture object
+ glDeleteTextures ( 1, &userData->textureId );
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+
+ eglDestroyContext(esContext->eglDisplay, esContext->eglContext);
+ eglDestroySurface(esContext->eglDisplay, esContext->eglSurface);
+ eglTerminate(esContext->eglDisplay);
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("Multiple Render Targets"), 320, 240, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/MultipleRenderTargets/MultipleRenderTargets.vcxproj b/samples/gles2_book/MultipleRenderTargets/MultipleRenderTargets.vcxproj
new file mode 100644
index 00000000..58ea2807
--- /dev/null
+++ b/samples/gles2_book/MultipleRenderTargets/MultipleRenderTargets.vcxproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{DD670DCB-2554-4FAE-B7C9-D7F0C3087C10}</ProjectGuid>
+ <RootNamespace>MultipleRenderTargets</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="MultipleRenderTargets.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/ParticleSystem/ParticleSystem.c b/samples/gles2_book/ParticleSystem/ParticleSystem.c
new file mode 100644
index 00000000..22141334
--- /dev/null
+++ b/samples/gles2_book/ParticleSystem/ParticleSystem.c
@@ -0,0 +1,294 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// ParticleSystem.c
+//
+// This is an example that demonstrates rendering a particle system
+// using a vertex shader and point sprites.
+//
+#include <stdlib.h>
+#include <math.h>
+#include "esUtil.h"
+
+#define NUM_PARTICLES 1000
+#define PARTICLE_SIZE 7
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint lifetimeLoc;
+ GLint startPositionLoc;
+ GLint endPositionLoc;
+
+ // Uniform location
+ GLint timeLoc;
+ GLint colorLoc;
+ GLint centerPositionLoc;
+ GLint samplerLoc;
+
+ // Texture handle
+ GLuint textureId;
+
+ // Particle vertex data
+ float particleData[ NUM_PARTICLES * PARTICLE_SIZE ];
+
+ // Current time
+ float time;
+
+} UserData;
+
+///
+// Load texture from disk
+//
+GLuint LoadTexture ( char *fileName )
+{
+ int width,
+ height;
+ char *buffer = esLoadTGA ( fileName, &width, &height );
+ GLuint texId;
+
+ if ( buffer == NULL )
+ {
+ esLogMessage ( "Error loading (%s) image.\n", fileName );
+ return 0;
+ }
+
+ glGenTextures ( 1, &texId );
+ glBindTexture ( GL_TEXTURE_2D, texId );
+
+ glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+
+ free ( buffer );
+
+ return texId;
+}
+
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ int i;
+
+ GLbyte vShaderStr[] =
+ "uniform float u_time; \n"
+ "uniform vec3 u_centerPosition; \n"
+ "attribute float a_lifetime; \n"
+ "attribute vec3 a_startPosition; \n"
+ "attribute vec3 a_endPosition; \n"
+ "varying float v_lifetime; \n"
+ "void main() \n"
+ "{ \n"
+ " if ( u_time <= a_lifetime ) \n"
+ " { \n"
+ " gl_Position.xyz = a_startPosition + \n"
+ " (u_time * a_endPosition); \n"
+ " gl_Position.xyz += u_centerPosition; \n"
+ " gl_Position.w = 1.0; \n"
+ " } \n"
+ " else \n"
+ " gl_Position = vec4( -1000, -1000, 0, 0 ); \n"
+ " v_lifetime = 1.0 - ( u_time / a_lifetime ); \n"
+ " v_lifetime = clamp ( v_lifetime, 0.0, 1.0 ); \n"
+ " gl_PointSize = ( v_lifetime * v_lifetime ) * 40.0; \n"
+ "}";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "uniform vec4 u_color; \n"
+ "varying float v_lifetime; \n"
+ "uniform sampler2D s_texture; \n"
+ "void main() \n"
+ "{ \n"
+ " vec4 texColor; \n"
+ " texColor = texture2D( s_texture, gl_PointCoord ); \n"
+ " gl_FragColor = vec4( u_color ) * texColor; \n"
+ " gl_FragColor.a *= v_lifetime; \n"
+ "} \n";
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->lifetimeLoc = glGetAttribLocation ( userData->programObject, "a_lifetime" );
+ userData->startPositionLoc = glGetAttribLocation ( userData->programObject, "a_startPosition" );
+ userData->endPositionLoc = glGetAttribLocation ( userData->programObject, "a_endPosition" );
+
+ // Get the uniform locations
+ userData->timeLoc = glGetUniformLocation ( userData->programObject, "u_time" );
+ userData->centerPositionLoc = glGetUniformLocation ( userData->programObject, "u_centerPosition" );
+ userData->colorLoc = glGetUniformLocation ( userData->programObject, "u_color" );
+ userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+
+ // Fill in particle data array
+ srand ( 0 );
+ for ( i = 0; i < NUM_PARTICLES; i++ )
+ {
+ float *particleData = &userData->particleData[i * PARTICLE_SIZE];
+
+ // Lifetime of particle
+ (*particleData++) = ( (float)(rand() % 10000) / 10000.0f );
+
+ // End position of particle
+ (*particleData++) = ( (float)(rand() % 10000) / 5000.0f ) - 1.0f;
+ (*particleData++) = ( (float)(rand() % 10000) / 5000.0f ) - 1.0f;
+ (*particleData++) = ( (float)(rand() % 10000) / 5000.0f ) - 1.0f;
+
+ // Start position of particle
+ (*particleData++) = ( (float)(rand() % 10000) / 40000.0f ) - 0.125f;
+ (*particleData++) = ( (float)(rand() % 10000) / 40000.0f ) - 0.125f;
+ (*particleData++) = ( (float)(rand() % 10000) / 40000.0f ) - 0.125f;
+
+ }
+
+ // Initialize time to cause reset on first update
+ userData->time = 1.0f;
+
+ userData->textureId = LoadTexture ( "smoke.tga" );
+ if ( userData->textureId <= 0 )
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+///
+// Update time-based variables
+//
+void Update ( ESContext *esContext, float deltaTime )
+{
+ UserData *userData = esContext->userData;
+
+ userData->time += deltaTime;
+
+ if ( userData->time >= 1.0f )
+ {
+ float centerPos[3];
+ float color[4];
+
+ userData->time = 0.0f;
+
+ // Pick a new start location and color
+ centerPos[0] = ( (float)(rand() % 10000) / 10000.0f ) - 0.5f;
+ centerPos[1] = ( (float)(rand() % 10000) / 10000.0f ) - 0.5f;
+ centerPos[2] = ( (float)(rand() % 10000) / 10000.0f ) - 0.5f;
+
+ glUniform3fv ( userData->centerPositionLoc, 1, &centerPos[0] );
+
+ // Random color
+ color[0] = ( (float)(rand() % 10000) / 20000.0f ) + 0.5f;
+ color[1] = ( (float)(rand() % 10000) / 20000.0f ) + 0.5f;
+ color[2] = ( (float)(rand() % 10000) / 20000.0f ) + 0.5f;
+ color[3] = 0.5;
+
+ glUniform4fv ( userData->colorLoc, 1, &color[0] );
+ }
+
+ // Load uniform time variable
+ glUniform1f ( userData->timeLoc, userData->time );
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex attributes
+ glVertexAttribPointer ( userData->lifetimeLoc, 1, GL_FLOAT,
+ GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat),
+ userData->particleData );
+
+ glVertexAttribPointer ( userData->endPositionLoc, 3, GL_FLOAT,
+ GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat),
+ &userData->particleData[1] );
+
+ glVertexAttribPointer ( userData->startPositionLoc, 3, GL_FLOAT,
+ GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat),
+ &userData->particleData[4] );
+
+
+ glEnableVertexAttribArray ( userData->lifetimeLoc );
+ glEnableVertexAttribArray ( userData->endPositionLoc );
+ glEnableVertexAttribArray ( userData->startPositionLoc );
+ // Blend particles
+ glEnable ( GL_BLEND );
+ glBlendFunc ( GL_SRC_ALPHA, GL_ONE );
+
+ // Bind the texture
+ glActiveTexture ( GL_TEXTURE0 );
+ glBindTexture ( GL_TEXTURE_2D, userData->textureId );
+ glEnable ( GL_TEXTURE_2D );
+
+ // Set the sampler texture unit to 0
+ glUniform1i ( userData->samplerLoc, 0 );
+
+ glDrawArrays( GL_POINTS, 0, NUM_PARTICLES );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Delete texture object
+ glDeleteTextures ( 1, &userData->textureId );
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("ParticleSystem"), 640, 480, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+ esRegisterUpdateFunc ( &esContext, Update );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/ParticleSystem/ParticleSystem.vcxproj b/samples/gles2_book/ParticleSystem/ParticleSystem.vcxproj
new file mode 100644
index 00000000..3e07a05f
--- /dev/null
+++ b/samples/gles2_book/ParticleSystem/ParticleSystem.vcxproj
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B9E5BFFC-D843-4E0E-9D3E-23913A613473}</ProjectGuid>
+ <RootNamespace>ParticleSystem</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /D /Y smoke.tga "$(outDir)"</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /D /Y smoke.tga "$(outDir)"</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="ParticleSystem.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/ParticleSystem/smoke.tga b/samples/gles2_book/ParticleSystem/smoke.tga
new file mode 100644
index 00000000..06a0705c
--- /dev/null
+++ b/samples/gles2_book/ParticleSystem/smoke.tga
Binary files differ
diff --git a/samples/gles2_book/PostSubBuffer/PostSubBuffer.c b/samples/gles2_book/PostSubBuffer/PostSubBuffer.c
new file mode 100644
index 00000000..0096ec31
--- /dev/null
+++ b/samples/gles2_book/PostSubBuffer/PostSubBuffer.c
@@ -0,0 +1,204 @@
+// Based on a sample from:
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// PostSubBuffer.c
+//
+// This is a simple example that draws a rotating cube in perspective
+// using a vertex shader to transform the object, posting only a subrectangle
+// to the window surface.
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+#define WINDOW_WIDTH 320
+#define WINDOW_HEIGHT 240
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+
+ // Uniform locations
+ GLint mvpLoc;
+
+ // Vertex daata
+ GLfloat *vertices;
+ GLushort *indices;
+ int numIndices;
+
+ // Rotation angle
+ GLfloat angle;
+
+ // MVP matrix
+ ESMatrix mvpMatrix;
+} UserData;
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "uniform mat4 u_mvpMatrix; \n"
+ "attribute vec4 a_position; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = u_mvpMatrix * a_position; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 ); \n"
+ "} \n";
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+
+ // Get the uniform locations
+ userData->mvpLoc = glGetUniformLocation( userData->programObject, "u_mvpMatrix" );
+
+ // Generate the vertex data
+ userData->numIndices = esGenCube( 1.0, &userData->vertices,
+ NULL, NULL, &userData->indices );
+
+ // Starting rotation angle for the cube
+ userData->angle = 45.0f;
+
+ // Clear the whole window surface.
+ glClearColor ( 0.0f, 0.0f, 1.0f, 0.0f );
+ glClear ( GL_COLOR_BUFFER_BIT );
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+ return TRUE;
+}
+
+
+///
+// Update MVP matrix based on time
+//
+void Update ( ESContext *esContext, float deltaTime )
+{
+ UserData *userData = (UserData*) esContext->userData;
+ ESMatrix perspective;
+ ESMatrix modelview;
+ float aspect;
+
+ // Compute a rotation angle based on time to rotate the cube
+ userData->angle += ( deltaTime * 40.0f );
+ if( userData->angle >= 360.0f )
+ userData->angle -= 360.0f;
+
+ // Compute the window aspect ratio
+ aspect = (GLfloat) esContext->width / (GLfloat) esContext->height;
+
+ // Generate a perspective matrix with a 60 degree FOV
+ esMatrixLoadIdentity( &perspective );
+ esPerspective( &perspective, 60.0f, aspect, 1.0f, 20.0f );
+
+ // Generate a model view matrix to rotate/translate the cube
+ esMatrixLoadIdentity( &modelview );
+
+ // Translate away from the viewer
+ esTranslate( &modelview, 0.0, 0.0, -2.0 );
+
+ // Rotate the cube
+ esRotate( &modelview, userData->angle, 1.0, 0.0, 1.0 );
+
+ // Compute the final MVP by multiplying the
+ // modevleiw and perspective matrices together
+ esMatrixMultiply( &userData->mvpMatrix, &modelview, &perspective );
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,
+ GL_FALSE, 3 * sizeof(GLfloat), userData->vertices );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+
+
+ // Load the MVP matrix
+ glUniformMatrix4fv( userData->mvpLoc, 1, GL_FALSE, (GLfloat*) &userData->mvpMatrix.m[0][0] );
+
+ // Draw the cube
+ glDrawElements ( GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_SHORT, userData->indices );
+
+ eglPostSubBufferNV ( esContext->eglDisplay, esContext->eglSurface, 60, 60, WINDOW_WIDTH - 120, WINDOW_HEIGHT - 120 );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ if ( userData->vertices != NULL )
+ {
+ free ( userData->vertices );
+ }
+
+ if ( userData->indices != NULL )
+ {
+ free ( userData->indices );
+ }
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("Simple Vertex Shader"), WINDOW_WIDTH, WINDOW_HEIGHT, ES_WINDOW_RGB | ES_WINDOW_POST_SUB_BUFFER_SUPPORTED );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+ esRegisterUpdateFunc ( &esContext, Update );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/PostSubBuffer/PostSubBuffer.vcxproj b/samples/gles2_book/PostSubBuffer/PostSubBuffer.vcxproj
new file mode 100644
index 00000000..488034b1
--- /dev/null
+++ b/samples/gles2_book/PostSubBuffer/PostSubBuffer.vcxproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{667CE95F-5DD8-4495-8C18-5CA8A175B12D}</ProjectGuid>
+ <RootNamespace>Simple_VertexShader</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="PostSubBuffer.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/Simple_Texture2D/Simple_Texture2D.c b/samples/gles2_book/Simple_Texture2D/Simple_Texture2D.c
new file mode 100644
index 00000000..b074608a
--- /dev/null
+++ b/samples/gles2_book/Simple_Texture2D/Simple_Texture2D.c
@@ -0,0 +1,198 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// Simple_Texture2D.c
+//
+// This is a simple example that draws a quad with a 2D
+// texture image. The purpose of this example is to demonstrate
+// the basics of 2D texturing
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+ GLint texCoordLoc;
+
+ // Sampler location
+ GLint samplerLoc;
+
+ // Texture handle
+ GLuint textureId;
+
+} UserData;
+
+///
+// Create a simple 2x2 texture image with four different colors
+//
+GLuint CreateSimpleTexture2D( )
+{
+ // Texture object handle
+ GLuint textureId;
+
+ // 2x2 Image, 3 bytes per pixel (R, G, B)
+ GLubyte pixels[4 * 3] =
+ {
+ 255, 0, 0, // Red
+ 0, 255, 0, // Green
+ 0, 0, 255, // Blue
+ 255, 255, 0 // Yellow
+ };
+
+ // Use tightly packed data
+ glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
+
+ // Generate a texture object
+ glGenTextures ( 1, &textureId );
+
+ // Bind the texture object
+ glBindTexture ( GL_TEXTURE_2D, textureId );
+
+ // Load the texture
+ glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+
+ // Set the filtering mode
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+
+ return textureId;
+
+}
+
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = a_position; \n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+ "} \n";
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+ userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" );
+
+ // Get the sampler location
+ userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
+
+ // Load the texture
+ userData->textureId = CreateSimpleTexture2D ();
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+ return TRUE;
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLfloat vVertices[] = { -0.5f, 0.5f, 0.0f, // Position 0
+ 0.0f, 0.0f, // TexCoord 0
+ -0.5f, -0.5f, 0.0f, // Position 1
+ 0.0f, 1.0f, // TexCoord 1
+ 0.5f, -0.5f, 0.0f, // Position 2
+ 1.0f, 1.0f, // TexCoord 2
+ 0.5f, 0.5f, 0.0f, // Position 3
+ 1.0f, 0.0f // TexCoord 3
+ };
+ GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), vVertices );
+ // Load the texture coordinate
+ glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3] );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+ glEnableVertexAttribArray ( userData->texCoordLoc );
+
+ // Bind the texture
+ glActiveTexture ( GL_TEXTURE0 );
+ glBindTexture ( GL_TEXTURE_2D, userData->textureId );
+
+ // Set the sampler texture unit to 0
+ glUniform1i ( userData->samplerLoc, 0 );
+
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Delete texture object
+ glDeleteTextures ( 1, &userData->textureId );
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("Simple Texture 2D"), 320, 240, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/Simple_Texture2D/Simple_Texture2D.vcxproj b/samples/gles2_book/Simple_Texture2D/Simple_Texture2D.vcxproj
new file mode 100644
index 00000000..2e755bbd
--- /dev/null
+++ b/samples/gles2_book/Simple_Texture2D/Simple_Texture2D.vcxproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{2E54D748-781B-4DF2-A1DD-B9384A821810}</ProjectGuid>
+ <RootNamespace>Simple_Texture2D</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Simple_Texture2D.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/Simple_TextureCubemap/Simple_TextureCubemap.c b/samples/gles2_book/Simple_TextureCubemap/Simple_TextureCubemap.c
new file mode 100644
index 00000000..302d844f
--- /dev/null
+++ b/samples/gles2_book/Simple_TextureCubemap/Simple_TextureCubemap.c
@@ -0,0 +1,229 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// Simple_TextureCubemap.c
+//
+// This is a simple example that draws a sphere with a cubemap image applied.
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+ GLint normalLoc;
+
+ // Sampler location
+ GLint samplerLoc;
+
+ // Texture handle
+ GLuint textureId;
+
+ // Vertex data
+ int numIndices;
+ GLfloat *vertices;
+ GLfloat *normals;
+ GLushort *indices;
+
+} UserData;
+
+///
+// Create a simple cubemap with a 1x1 face with a different
+// color for each face
+GLuint CreateSimpleTextureCubemap( )
+{
+ GLuint textureId;
+ // Six 1x1 RGB faces
+ GLubyte cubePixels[6][3] =
+ {
+ // Face 0 - Red
+ 255, 0, 0,
+ // Face 1 - Green,
+ 0, 255, 0,
+ // Face 3 - Blue
+ 0, 0, 255,
+ // Face 4 - Yellow
+ 255, 255, 0,
+ // Face 5 - Purple
+ 255, 0, 255,
+ // Face 6 - White
+ 255, 255, 255
+ };
+
+ // Generate a texture object
+ glGenTextures ( 1, &textureId );
+
+ // Bind the texture object
+ glBindTexture ( GL_TEXTURE_CUBE_MAP, textureId );
+
+ // Load the cube face - Positive X
+ glTexImage2D ( GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB, 1, 1, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[0] );
+
+ // Load the cube face - Negative X
+ glTexImage2D ( GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB, 1, 1, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[1] );
+
+ // Load the cube face - Positive Y
+ glTexImage2D ( GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGB, 1, 1, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[2] );
+
+ // Load the cube face - Negative Y
+ glTexImage2D ( GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, 1, 1, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[3] );
+
+ // Load the cube face - Positive Z
+ glTexImage2D ( GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGB, 1, 1, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[4] );
+
+ // Load the cube face - Negative Z
+ glTexImage2D ( GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGB, 1, 1, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[5] );
+
+ // Set the filtering mode
+ glTexParameteri ( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri ( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+
+ return textureId;
+
+}
+
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "attribute vec4 a_position; \n"
+ "attribute vec3 a_normal; \n"
+ "varying vec3 v_normal; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = a_position; \n"
+ " v_normal = a_normal; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "varying vec3 v_normal; \n"
+ "uniform samplerCube s_texture; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = textureCube( s_texture, v_normal );\n"
+ "} \n";
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+ userData->normalLoc = glGetAttribLocation ( userData->programObject, "a_normal" );
+
+ // Get the sampler locations
+ userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
+
+ // Load the texture
+ userData->textureId = CreateSimpleTextureCubemap ();
+
+ // Generate the vertex data
+ userData->numIndices = esGenSphere ( 20, 0.75f, &userData->vertices, &userData->normals,
+ NULL, &userData->indices );
+
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+ return TRUE;
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+
+ glCullFace ( GL_BACK );
+ glEnable ( GL_CULL_FACE );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,
+ GL_FALSE, 0, userData->vertices );
+ // Load the normal
+ glVertexAttribPointer ( userData->normalLoc, 3, GL_FLOAT,
+ GL_FALSE, 0, userData->normals );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+ glEnableVertexAttribArray ( userData->normalLoc );
+
+ // Bind the texture
+ glActiveTexture ( GL_TEXTURE0 );
+ glBindTexture ( GL_TEXTURE_CUBE_MAP, userData->textureId );
+
+ // Set the sampler texture unit to 0
+ glUniform1i ( userData->samplerLoc, 0 );
+
+ glDrawElements ( GL_TRIANGLES, userData->numIndices,
+ GL_UNSIGNED_SHORT, userData->indices );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Delete texture object
+ glDeleteTextures ( 1, &userData->textureId );
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+
+ free ( userData->vertices );
+ free ( userData->normals );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("Simple Texture Cubemap"), 320, 240, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/Simple_TextureCubemap/Simple_TextureCubemap.vcxproj b/samples/gles2_book/Simple_TextureCubemap/Simple_TextureCubemap.vcxproj
new file mode 100644
index 00000000..df2bc01c
--- /dev/null
+++ b/samples/gles2_book/Simple_TextureCubemap/Simple_TextureCubemap.vcxproj
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{5EE56061-643D-406E-B42D-4299D2411056}</ProjectGuid>
+ <RootNamespace>Simple_TextureCubemap</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <ProjectReference>
+ <UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
+ </ProjectReference>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Simple_TextureCubemap.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/Simple_VertexShader/Simple_VertexShader.c b/samples/gles2_book/Simple_VertexShader/Simple_VertexShader.c
new file mode 100644
index 00000000..df5c98d6
--- /dev/null
+++ b/samples/gles2_book/Simple_VertexShader/Simple_VertexShader.c
@@ -0,0 +1,194 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// Simple_VertexShader.c
+//
+// This is a simple example that draws a rotating cube in perspective
+// using a vertex shader to transform the object
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+
+ // Uniform locations
+ GLint mvpLoc;
+
+ // Vertex daata
+ GLfloat *vertices;
+ GLushort *indices;
+ int numIndices;
+
+ // Rotation angle
+ GLfloat angle;
+
+ // MVP matrix
+ ESMatrix mvpMatrix;
+} UserData;
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "uniform mat4 u_mvpMatrix; \n"
+ "attribute vec4 a_position; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = u_mvpMatrix * a_position; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 ); \n"
+ "} \n";
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+
+ // Get the uniform locations
+ userData->mvpLoc = glGetUniformLocation( userData->programObject, "u_mvpMatrix" );
+
+ // Generate the vertex data
+ userData->numIndices = esGenCube( 1.0, &userData->vertices,
+ NULL, NULL, &userData->indices );
+
+ // Starting rotation angle for the cube
+ userData->angle = 45.0f;
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+ return TRUE;
+}
+
+
+///
+// Update MVP matrix based on time
+//
+void Update ( ESContext *esContext, float deltaTime )
+{
+ UserData *userData = (UserData*) esContext->userData;
+ ESMatrix perspective;
+ ESMatrix modelview;
+ float aspect;
+
+ // Compute a rotation angle based on time to rotate the cube
+ userData->angle += ( deltaTime * 40.0f );
+ if( userData->angle >= 360.0f )
+ userData->angle -= 360.0f;
+
+ // Compute the window aspect ratio
+ aspect = (GLfloat) esContext->width / (GLfloat) esContext->height;
+
+ // Generate a perspective matrix with a 60 degree FOV
+ esMatrixLoadIdentity( &perspective );
+ esPerspective( &perspective, 60.0f, aspect, 1.0f, 20.0f );
+
+ // Generate a model view matrix to rotate/translate the cube
+ esMatrixLoadIdentity( &modelview );
+
+ // Translate away from the viewer
+ esTranslate( &modelview, 0.0, 0.0, -2.0 );
+
+ // Rotate the cube
+ esRotate( &modelview, userData->angle, 1.0, 0.0, 1.0 );
+
+ // Compute the final MVP by multiplying the
+ // modevleiw and perspective matrices together
+ esMatrixMultiply( &userData->mvpMatrix, &modelview, &perspective );
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,
+ GL_FALSE, 3 * sizeof(GLfloat), userData->vertices );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+
+
+ // Load the MVP matrix
+ glUniformMatrix4fv( userData->mvpLoc, 1, GL_FALSE, (GLfloat*) &userData->mvpMatrix.m[0][0] );
+
+ // Draw the cube
+ glDrawElements ( GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_SHORT, userData->indices );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ if ( userData->vertices != NULL )
+ {
+ free ( userData->vertices );
+ }
+
+ if ( userData->indices != NULL )
+ {
+ free ( userData->indices );
+ }
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("Simple Vertex Shader"), 320, 240, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+ esRegisterUpdateFunc ( &esContext, Update );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/Simple_VertexShader/Simple_VertexShader.vcxproj b/samples/gles2_book/Simple_VertexShader/Simple_VertexShader.vcxproj
new file mode 100644
index 00000000..b3a2928f
--- /dev/null
+++ b/samples/gles2_book/Simple_VertexShader/Simple_VertexShader.vcxproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{667CE95F-5DD8-4395-8C18-5CA8A175B12D}</ProjectGuid>
+ <RootNamespace>Simple_VertexShader</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Simple_VertexShader.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/Stencil_Test/Stencil_Test.c b/samples/gles2_book/Stencil_Test/Stencil_Test.c
new file mode 100644
index 00000000..4996ccfc
--- /dev/null
+++ b/samples/gles2_book/Stencil_Test/Stencil_Test.c
@@ -0,0 +1,273 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// Stencil_Test.c
+//
+// This example shows various stencil buffer
+// operations.
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+
+ // Uniform locations
+ GLint colorLoc;
+
+} UserData;
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "attribute vec4 a_position; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = a_position; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "uniform vec4 u_color; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = u_color; \n"
+ "} \n";
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+
+ // Get the sampler location
+ userData->colorLoc = glGetUniformLocation ( userData->programObject, "u_color" );
+
+ // Set the clear color
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+
+ // Set the stencil clear value
+ glClearStencil ( 0x1 );
+
+ // Set the depth clear value
+ glClearDepthf( 0.75f );
+
+ // Enable the depth and stencil tests
+ glEnable( GL_DEPTH_TEST );
+ glEnable( GL_STENCIL_TEST );
+
+ return TRUE;
+}
+
+///
+// Initialize the stencil buffer values, and then use those
+// values to control rendering
+//
+void Draw ( ESContext *esContext )
+{
+ int i;
+
+ UserData *userData = esContext->userData;
+
+ GLfloat vVertices[] = {
+ -0.75f, 0.25f, 0.50f, // Quad #0
+ -0.25f, 0.25f, 0.50f,
+ -0.25f, 0.75f, 0.50f,
+ -0.75f, 0.75f, 0.50f,
+ 0.25f, 0.25f, 0.90f, // Quad #1
+ 0.75f, 0.25f, 0.90f,
+ 0.75f, 0.75f, 0.90f,
+ 0.25f, 0.75f, 0.90f,
+ -0.75f, -0.75f, 0.50f, // Quad #2
+ -0.25f, -0.75f, 0.50f,
+ -0.25f, -0.25f, 0.50f,
+ -0.75f, -0.25f, 0.50f,
+ 0.25f, -0.75f, 0.50f, // Quad #3
+ 0.75f, -0.75f, 0.50f,
+ 0.75f, -0.25f, 0.50f,
+ 0.25f, -0.25f, 0.50f,
+ -1.00f, -1.00f, 0.00f, // Big Quad
+ 1.00f, -1.00f, 0.00f,
+ 1.00f, 1.00f, 0.00f,
+ -1.00f, 1.00f, 0.00f
+ };
+
+ GLubyte indices[][6] = {
+ { 0, 1, 2, 0, 2, 3 }, // Quad #0
+ { 4, 5, 6, 4, 6, 7 }, // Quad #1
+ { 8, 9, 10, 8, 10, 11 }, // Quad #2
+ { 12, 13, 14, 12, 14, 15 }, // Quad #3
+ { 16, 17, 18, 16, 18, 19 } // Big Quad
+ };
+
+#define NumTests 4
+ GLfloat colors[NumTests][4] = {
+ { 1.0f, 0.0f, 0.0f, 1.0f },
+ { 0.0f, 1.0f, 0.0f, 1.0f },
+ { 0.0f, 0.0f, 1.0f, 1.0f },
+ { 1.0f, 1.0f, 0.0f, 0.0f }
+ };
+
+ GLint numStencilBits;
+ GLuint stencilValues[NumTests] = {
+ 0x7, // Result of test 0
+ 0x0, // Result of test 1
+ 0x2, // Result of test 2
+ 0xff // Result of test 3. We need to fill this
+ // value in a run-time
+ };
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color, depth, and stencil buffers. At this
+ // point, the stencil buffer will be 0x1 for all pixels
+ glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,
+ GL_FALSE, 0, vVertices );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+
+ // Test 0:
+ //
+ // Initialize upper-left region. In this case, the
+ // stencil-buffer values will be replaced because the
+ // stencil test for the rendered pixels will fail the
+ // stencil test, which is
+ //
+ // ref mask stencil mask
+ // ( 0x7 & 0x3 ) < ( 0x1 & 0x7 )
+ //
+ // The value in the stencil buffer for these pixels will
+ // be 0x7.
+ //
+ glStencilFunc( GL_LESS, 0x7, 0x3 );
+ glStencilOp( GL_REPLACE, GL_DECR, GL_DECR );
+ glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[0] );
+
+ // Test 1:
+ //
+ // Initialize the upper-right region. Here, we'll decrement
+ // the stencil-buffer values where the stencil test passes
+ // but the depth test fails. The stencil test is
+ //
+ // ref mask stencil mask
+ // ( 0x3 & 0x3 ) > ( 0x1 & 0x3 )
+ //
+ // but where the geometry fails the depth test. The
+ // stencil values for these pixels will be 0x0.
+ //
+ glStencilFunc( GL_GREATER, 0x3, 0x3 );
+ glStencilOp( GL_KEEP, GL_DECR, GL_KEEP );
+ glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[1] );
+
+ // Test 2:
+ //
+ // Initialize the lower-left region. Here we'll increment
+ // (with saturation) the stencil value where both the
+ // stencil and depth tests pass. The stencil test for
+ // these pixels will be
+ //
+ // ref mask stencil mask
+ // ( 0x1 & 0x3 ) == ( 0x1 & 0x3 )
+ //
+ // The stencil values for these pixels will be 0x2.
+ //
+ glStencilFunc( GL_EQUAL, 0x1, 0x3 );
+ glStencilOp( GL_KEEP, GL_INCR, GL_INCR );
+ glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[2] );
+
+ // Test 3:
+ //
+ // Finally, initialize the lower-right region. We'll invert
+ // the stencil value where the stencil tests fails. The
+ // stencil test for these pixels will be
+ //
+ // ref mask stencil mask
+ // ( 0x2 & 0x1 ) == ( 0x1 & 0x1 )
+ //
+ // The stencil value here will be set to ~((2^s-1) & 0x1),
+ // (with the 0x1 being from the stencil clear value),
+ // where 's' is the number of bits in the stencil buffer
+ //
+ glStencilFunc( GL_EQUAL, 0x2, 0x1 );
+ glStencilOp( GL_INVERT, GL_KEEP, GL_KEEP );
+ glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[3] );
+
+ // Since we don't know at compile time how many stecil bits are present,
+ // we'll query, and update the value correct value in the
+ // stencilValues arrays for the fourth tests. We'll use this value
+ // later in rendering.
+ glGetIntegerv( GL_STENCIL_BITS, &numStencilBits );
+
+ stencilValues[3] = ~(((1 << numStencilBits) - 1) & 0x1) & 0xff;
+
+ // Use the stencil buffer for controlling where rendering will
+ // occur. We diable writing to the stencil buffer so we
+ // can test against them without modifying the values we
+ // generated.
+ glStencilMask( 0x0 );
+
+ for ( i = 0; i < NumTests; ++i )
+ {
+ glStencilFunc( GL_EQUAL, stencilValues[i], 0xff );
+ glUniform4fv( userData->colorLoc, 1, colors[i] );
+ glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[4] );
+ }
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("Stencil Test"), 320, 240,
+ ES_WINDOW_RGB | ES_WINDOW_DEPTH | ES_WINDOW_STENCIL );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/Stencil_Test/Stencil_Test.vcxproj b/samples/gles2_book/Stencil_Test/Stencil_Test.vcxproj
new file mode 100644
index 00000000..2b829a94
--- /dev/null
+++ b/samples/gles2_book/Stencil_Test/Stencil_Test.vcxproj
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{EEACE995-26BC-4D56-A8B3-3E7A9AB3EB26}</ProjectGuid>
+ <RootNamespace>Stencil_Test</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Stencil_Test.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/gles2_book/TextureWrap/TextureWrap.c b/samples/gles2_book/TextureWrap/TextureWrap.c
new file mode 100644
index 00000000..3e958ddf
--- /dev/null
+++ b/samples/gles2_book/TextureWrap/TextureWrap.c
@@ -0,0 +1,254 @@
+//
+// Book: OpenGL(R) ES 2.0 Programming Guide
+// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10: 0321502795
+// ISBN-13: 9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs: http://safari.informit.com/9780321563835
+// http://www.opengles-book.com
+//
+
+// TextureWrap.c
+//
+// This is an example that demonstrates the three texture
+// wrap modes available on 2D textures
+//
+#include <stdlib.h>
+#include "esUtil.h"
+
+typedef struct
+{
+ // Handle to a program object
+ GLuint programObject;
+
+ // Attribute locations
+ GLint positionLoc;
+ GLint texCoordLoc;
+
+ // Sampler location
+ GLint samplerLoc;
+
+ // Offset location
+ GLint offsetLoc;
+
+ // Texture handle
+ GLuint textureId;
+
+} UserData;
+
+///
+// Generate an RGB8 checkerboard image
+//
+GLubyte* GenCheckImage( int width, int height, int checkSize )
+{
+ int x,
+ y;
+ GLubyte *pixels = malloc( width * height * 3 );
+
+ if ( pixels == NULL )
+ return NULL;
+
+ for ( y = 0; y < height; y++ )
+ for ( x = 0; x < width; x++ )
+ {
+ GLubyte rColor = 0;
+ GLubyte bColor = 0;
+
+ if ( ( x / checkSize ) % 2 == 0 )
+ {
+ rColor = 255 * ( ( y / checkSize ) % 2 );
+ bColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) );
+ }
+ else
+ {
+ bColor = 255 * ( ( y / checkSize ) % 2 );
+ rColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) );
+ }
+
+ pixels[(y * height + x) * 3] = rColor;
+ pixels[(y * height + x) * 3 + 1] = 0;
+ pixels[(y * height + x) * 3 + 2] = bColor;
+ }
+
+ return pixels;
+}
+
+///
+// Create a mipmapped 2D texture image
+//
+GLuint CreateTexture2D( )
+{
+ // Texture object handle
+ GLuint textureId;
+ int width = 256,
+ height = 256;
+ GLubyte *pixels;
+
+ pixels = GenCheckImage( width, height, 64 );
+ if ( pixels == NULL )
+ return 0;
+
+ // Generate a texture object
+ glGenTextures ( 1, &textureId );
+
+ // Bind the texture object
+ glBindTexture ( GL_TEXTURE_2D, textureId );
+
+ // Load mipmap level 0
+ glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height,
+ 0, GL_RGB, GL_UNSIGNED_BYTE, pixels );
+
+ // Set the filtering mode
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+ return textureId;
+
+}
+
+
+///
+// Initialize the shader and program object
+//
+int Init ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLbyte vShaderStr[] =
+ "uniform float u_offset; \n"
+ "attribute vec4 a_position; \n"
+ "attribute vec2 a_texCoord; \n"
+ "varying vec2 v_texCoord; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = a_position; \n"
+ " gl_Position.x += u_offset;\n"
+ " v_texCoord = a_texCoord; \n"
+ "} \n";
+
+ GLbyte fShaderStr[] =
+ "precision mediump float; \n"
+ "varying vec2 v_texCoord; \n"
+ "uniform sampler2D s_texture; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+ "} \n";
+
+ // Load the shaders and get a linked program object
+ userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
+
+ // Get the attribute locations
+ userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
+ userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" );
+
+ // Get the sampler location
+ userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
+
+ // Get the offset location
+ userData->offsetLoc = glGetUniformLocation( userData->programObject, "u_offset" );
+
+ // Load the texture
+ userData->textureId = CreateTexture2D ();
+
+ glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
+ return TRUE;
+}
+
+///
+// Draw a triangle using the shader pair created in Init()
+//
+void Draw ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+ GLfloat vVertices[] = { -0.3f, 0.3f, 0.0f, 1.0f, // Position 0
+ -1.0f, -1.0f, // TexCoord 0
+ -0.3f, -0.3f, 0.0f, 1.0f, // Position 1
+ -1.0f, 2.0f, // TexCoord 1
+ 0.3f, -0.3f, 0.0f, 1.0f, // Position 2
+ 2.0f, 2.0f, // TexCoord 2
+ 0.3f, 0.3f, 0.0f, 1.0f, // Position 3
+ 2.0f, -1.0f // TexCoord 3
+ };
+ GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+ // Set the viewport
+ glViewport ( 0, 0, esContext->width, esContext->height );
+
+ // Clear the color buffer
+ glClear ( GL_COLOR_BUFFER_BIT );
+
+ // Use the program object
+ glUseProgram ( userData->programObject );
+
+ // Load the vertex position
+ glVertexAttribPointer ( userData->positionLoc, 4, GL_FLOAT,
+ GL_FALSE, 6 * sizeof(GLfloat), vVertices );
+ // Load the texture coordinate
+ glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT,
+ GL_FALSE, 6 * sizeof(GLfloat), &vVertices[4] );
+
+ glEnableVertexAttribArray ( userData->positionLoc );
+ glEnableVertexAttribArray ( userData->texCoordLoc );
+
+ // Bind the texture
+ glActiveTexture ( GL_TEXTURE0 );
+ glBindTexture ( GL_TEXTURE_2D, userData->textureId );
+
+ // Set the sampler texture unit to 0
+ glUniform1i ( userData->samplerLoc, 0 );
+
+ // Draw quad with repeat wrap mode
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ glUniform1f ( userData->offsetLoc, -0.7f );
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ // Draw quad with clamp to edge wrap mode
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glUniform1f ( userData->offsetLoc, 0.0f );
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ // Draw quad with mirrored repeat
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT );
+ glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT );
+ glUniform1f ( userData->offsetLoc, 0.7f );
+ glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
+
+ eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
+}
+
+///
+// Cleanup
+//
+void ShutDown ( ESContext *esContext )
+{
+ UserData *userData = esContext->userData;
+
+ // Delete texture object
+ glDeleteTextures ( 1, &userData->textureId );
+
+ // Delete program object
+ glDeleteProgram ( userData->programObject );
+}
+
+
+int main ( int argc, char *argv[] )
+{
+ ESContext esContext;
+ UserData userData;
+
+ esInitContext ( &esContext );
+ esContext.userData = &userData;
+
+ esCreateWindow ( &esContext, TEXT("Texture Wrap"), 640, 480, ES_WINDOW_RGB );
+
+ if ( !Init ( &esContext ) )
+ return 0;
+
+ esRegisterDrawFunc ( &esContext, Draw );
+
+ esMainLoop ( &esContext );
+
+ ShutDown ( &esContext );
+}
diff --git a/samples/gles2_book/TextureWrap/TextureWrap.vcxproj b/samples/gles2_book/TextureWrap/TextureWrap.vcxproj
new file mode 100644
index 00000000..076b8b67
--- /dev/null
+++ b/samples/gles2_book/TextureWrap/TextureWrap.vcxproj
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{CC1DE9A2-B456-4565-9C21-932253E969B9}</ProjectGuid>
+ <RootNamespace>TextureWrap</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>../Common;../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="TextureWrap.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\esUtil.vcxproj">
+ <Project>{47c93f52-ab4e-4ff9-8d4f-b38cd60a183f}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/samples.sln b/samples/samples.sln
new file mode 100644
index 00000000..54d58541
--- /dev/null
+++ b/samples/samples.sln
@@ -0,0 +1,177 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "esUtil", "gles2_book\Common\esUtil.vcxproj", "{47C93F52-AB4E-4FF9-8D4F-B38CD60A183F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hello_Triangle", "gles2_book\Hello_Triangle\Hello_Triangle.vcxproj", "{8278251F-6C1F-4D80-8499-FA7B590FAFE6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MipMap2D", "gles2_book\MipMap2D\MipMap2D.vcxproj", "{4E69AC1F-1C7A-4D58-917C-E764FBEB489A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MultiTexture", "gles2_book\MultiTexture\MultiTexture.vcxproj", "{120CFF94-ED4B-4C5B-9587-9E40889F15F7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ParticleSystem", "gles2_book\ParticleSystem\ParticleSystem.vcxproj", "{B9E5BFFC-D843-4E0E-9D3E-23913A613473}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple_Texture2D", "gles2_book\Simple_Texture2D\Simple_Texture2D.vcxproj", "{2E54D748-781B-4DF2-A1DD-B9384A821810}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple_TextureCubemap", "gles2_book\Simple_TextureCubemap\Simple_TextureCubemap.vcxproj", "{5EE56061-643D-406E-B42D-4299D2411056}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple_VertexShader", "gles2_book\Simple_VertexShader\Simple_VertexShader.vcxproj", "{667CE95F-5DD8-4395-8C18-5CA8A175B12D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Stencil_Test", "gles2_book\Stencil_Test\Stencil_Test.vcxproj", "{EEACE995-26BC-4D56-A8B3-3E7A9AB3EB26}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TextureWrap", "gles2_book\TextureWrap\TextureWrap.vcxproj", "{CC1DE9A2-B456-4565-9C21-932253E969B9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libEGL", "..\src\libEGL\libEGL.vcxproj", "{E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libGLESv2", "..\src\libGLESv2\libGLESv2.vcxproj", "{B5871A7A-968C-42E3-A33B-981E6F448E78}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "translator_hlsl", "..\src\compiler\translator_hlsl.vcxproj", "{5620F0E4-6C43-49BC-A178-B804E1A0C3A7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "essl_to_hlsl", "translator\essl_to_hlsl.vcxproj", "{E12EA115-EBC7-47C2-B651-30A0CE986025}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "translator_common", "..\src\compiler\translator_common.vcxproj", "{5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PostSubBuffer", "gles2_book\PostSubBuffer\PostSubBuffer.vcxproj", "{667CE95F-5DD8-4495-8C18-5CA8A175B12D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "preprocessor", "..\src\compiler\preprocessor\preprocessor.vcxproj", "{FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simple_Instancing", "angle\Simple_Instancing\Simple_Instancing.vcxproj", "{EB6E138B-9DE5-41E8-A127-3675AA2BA607}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MultipleRenderTargets", "gles2_book\MultipleRenderTargets\MultipleRenderTargets.vcxproj", "{DD670DCB-2554-4FAE-B7C9-D7F0C3087C10}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {47C93F52-AB4E-4FF9-8D4F-B38CD60A183F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {47C93F52-AB4E-4FF9-8D4F-B38CD60A183F}.Debug|Win32.Build.0 = Debug|Win32
+ {47C93F52-AB4E-4FF9-8D4F-B38CD60A183F}.Debug|x64.ActiveCfg = Debug|Win32
+ {47C93F52-AB4E-4FF9-8D4F-B38CD60A183F}.Release|Win32.ActiveCfg = Release|Win32
+ {47C93F52-AB4E-4FF9-8D4F-B38CD60A183F}.Release|Win32.Build.0 = Release|Win32
+ {47C93F52-AB4E-4FF9-8D4F-B38CD60A183F}.Release|x64.ActiveCfg = Release|Win32
+ {8278251F-6C1F-4D80-8499-FA7B590FAFE6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8278251F-6C1F-4D80-8499-FA7B590FAFE6}.Debug|Win32.Build.0 = Debug|Win32
+ {8278251F-6C1F-4D80-8499-FA7B590FAFE6}.Debug|x64.ActiveCfg = Debug|Win32
+ {8278251F-6C1F-4D80-8499-FA7B590FAFE6}.Release|Win32.ActiveCfg = Release|Win32
+ {8278251F-6C1F-4D80-8499-FA7B590FAFE6}.Release|Win32.Build.0 = Release|Win32
+ {8278251F-6C1F-4D80-8499-FA7B590FAFE6}.Release|x64.ActiveCfg = Release|Win32
+ {4E69AC1F-1C7A-4D58-917C-E764FBEB489A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4E69AC1F-1C7A-4D58-917C-E764FBEB489A}.Debug|Win32.Build.0 = Debug|Win32
+ {4E69AC1F-1C7A-4D58-917C-E764FBEB489A}.Debug|x64.ActiveCfg = Debug|Win32
+ {4E69AC1F-1C7A-4D58-917C-E764FBEB489A}.Release|Win32.ActiveCfg = Release|Win32
+ {4E69AC1F-1C7A-4D58-917C-E764FBEB489A}.Release|Win32.Build.0 = Release|Win32
+ {4E69AC1F-1C7A-4D58-917C-E764FBEB489A}.Release|x64.ActiveCfg = Release|Win32
+ {120CFF94-ED4B-4C5B-9587-9E40889F15F7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {120CFF94-ED4B-4C5B-9587-9E40889F15F7}.Debug|Win32.Build.0 = Debug|Win32
+ {120CFF94-ED4B-4C5B-9587-9E40889F15F7}.Debug|x64.ActiveCfg = Debug|Win32
+ {120CFF94-ED4B-4C5B-9587-9E40889F15F7}.Release|Win32.ActiveCfg = Release|Win32
+ {120CFF94-ED4B-4C5B-9587-9E40889F15F7}.Release|Win32.Build.0 = Release|Win32
+ {120CFF94-ED4B-4C5B-9587-9E40889F15F7}.Release|x64.ActiveCfg = Release|Win32
+ {B9E5BFFC-D843-4E0E-9D3E-23913A613473}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B9E5BFFC-D843-4E0E-9D3E-23913A613473}.Debug|Win32.Build.0 = Debug|Win32
+ {B9E5BFFC-D843-4E0E-9D3E-23913A613473}.Debug|x64.ActiveCfg = Debug|Win32
+ {B9E5BFFC-D843-4E0E-9D3E-23913A613473}.Release|Win32.ActiveCfg = Release|Win32
+ {B9E5BFFC-D843-4E0E-9D3E-23913A613473}.Release|Win32.Build.0 = Release|Win32
+ {B9E5BFFC-D843-4E0E-9D3E-23913A613473}.Release|x64.ActiveCfg = Release|Win32
+ {2E54D748-781B-4DF2-A1DD-B9384A821810}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2E54D748-781B-4DF2-A1DD-B9384A821810}.Debug|Win32.Build.0 = Debug|Win32
+ {2E54D748-781B-4DF2-A1DD-B9384A821810}.Debug|x64.ActiveCfg = Debug|Win32
+ {2E54D748-781B-4DF2-A1DD-B9384A821810}.Release|Win32.ActiveCfg = Release|Win32
+ {2E54D748-781B-4DF2-A1DD-B9384A821810}.Release|Win32.Build.0 = Release|Win32
+ {2E54D748-781B-4DF2-A1DD-B9384A821810}.Release|x64.ActiveCfg = Release|Win32
+ {5EE56061-643D-406E-B42D-4299D2411056}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5EE56061-643D-406E-B42D-4299D2411056}.Debug|Win32.Build.0 = Debug|Win32
+ {5EE56061-643D-406E-B42D-4299D2411056}.Debug|x64.ActiveCfg = Debug|Win32
+ {5EE56061-643D-406E-B42D-4299D2411056}.Release|Win32.ActiveCfg = Release|Win32
+ {5EE56061-643D-406E-B42D-4299D2411056}.Release|Win32.Build.0 = Release|Win32
+ {5EE56061-643D-406E-B42D-4299D2411056}.Release|x64.ActiveCfg = Release|Win32
+ {667CE95F-5DD8-4395-8C18-5CA8A175B12D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {667CE95F-5DD8-4395-8C18-5CA8A175B12D}.Debug|Win32.Build.0 = Debug|Win32
+ {667CE95F-5DD8-4395-8C18-5CA8A175B12D}.Debug|x64.ActiveCfg = Debug|Win32
+ {667CE95F-5DD8-4395-8C18-5CA8A175B12D}.Release|Win32.ActiveCfg = Release|Win32
+ {667CE95F-5DD8-4395-8C18-5CA8A175B12D}.Release|Win32.Build.0 = Release|Win32
+ {667CE95F-5DD8-4395-8C18-5CA8A175B12D}.Release|x64.ActiveCfg = Release|Win32
+ {EEACE995-26BC-4D56-A8B3-3E7A9AB3EB26}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EEACE995-26BC-4D56-A8B3-3E7A9AB3EB26}.Debug|Win32.Build.0 = Debug|Win32
+ {EEACE995-26BC-4D56-A8B3-3E7A9AB3EB26}.Debug|x64.ActiveCfg = Debug|Win32
+ {EEACE995-26BC-4D56-A8B3-3E7A9AB3EB26}.Release|Win32.ActiveCfg = Release|Win32
+ {EEACE995-26BC-4D56-A8B3-3E7A9AB3EB26}.Release|Win32.Build.0 = Release|Win32
+ {EEACE995-26BC-4D56-A8B3-3E7A9AB3EB26}.Release|x64.ActiveCfg = Release|Win32
+ {CC1DE9A2-B456-4565-9C21-932253E969B9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CC1DE9A2-B456-4565-9C21-932253E969B9}.Debug|Win32.Build.0 = Debug|Win32
+ {CC1DE9A2-B456-4565-9C21-932253E969B9}.Debug|x64.ActiveCfg = Debug|Win32
+ {CC1DE9A2-B456-4565-9C21-932253E969B9}.Release|Win32.ActiveCfg = Release|Win32
+ {CC1DE9A2-B456-4565-9C21-932253E969B9}.Release|Win32.Build.0 = Release|Win32
+ {CC1DE9A2-B456-4565-9C21-932253E969B9}.Release|x64.ActiveCfg = Release|Win32
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|Win32.Build.0 = Debug|Win32
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|x64.ActiveCfg = Debug|x64
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|x64.Build.0 = Debug|x64
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|Win32.ActiveCfg = Release|Win32
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|Win32.Build.0 = Release|Win32
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|x64.ActiveCfg = Release|x64
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|x64.Build.0 = Release|x64
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|Win32.Build.0 = Debug|Win32
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|x64.ActiveCfg = Debug|x64
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|x64.Build.0 = Debug|x64
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|Win32.ActiveCfg = Release|Win32
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|Win32.Build.0 = Release|Win32
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|x64.ActiveCfg = Release|x64
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|x64.Build.0 = Release|x64
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Debug|Win32.Build.0 = Debug|Win32
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Debug|x64.ActiveCfg = Debug|x64
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Debug|x64.Build.0 = Debug|x64
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Release|Win32.ActiveCfg = Release|Win32
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Release|Win32.Build.0 = Release|Win32
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Release|x64.ActiveCfg = Release|x64
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Release|x64.Build.0 = Release|x64
+ {E12EA115-EBC7-47C2-B651-30A0CE986025}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E12EA115-EBC7-47C2-B651-30A0CE986025}.Debug|Win32.Build.0 = Debug|Win32
+ {E12EA115-EBC7-47C2-B651-30A0CE986025}.Debug|x64.ActiveCfg = Debug|Win32
+ {E12EA115-EBC7-47C2-B651-30A0CE986025}.Release|Win32.ActiveCfg = Release|Win32
+ {E12EA115-EBC7-47C2-B651-30A0CE986025}.Release|Win32.Build.0 = Release|Win32
+ {E12EA115-EBC7-47C2-B651-30A0CE986025}.Release|x64.ActiveCfg = Release|Win32
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|Win32.Build.0 = Debug|Win32
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|x64.ActiveCfg = Debug|x64
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|x64.Build.0 = Debug|x64
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|Win32.ActiveCfg = Release|Win32
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|Win32.Build.0 = Release|Win32
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|x64.ActiveCfg = Release|x64
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|x64.Build.0 = Release|x64
+ {667CE95F-5DD8-4495-8C18-5CA8A175B12D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {667CE95F-5DD8-4495-8C18-5CA8A175B12D}.Debug|Win32.Build.0 = Debug|Win32
+ {667CE95F-5DD8-4495-8C18-5CA8A175B12D}.Debug|x64.ActiveCfg = Debug|Win32
+ {667CE95F-5DD8-4495-8C18-5CA8A175B12D}.Release|Win32.ActiveCfg = Release|Win32
+ {667CE95F-5DD8-4495-8C18-5CA8A175B12D}.Release|Win32.Build.0 = Release|Win32
+ {667CE95F-5DD8-4495-8C18-5CA8A175B12D}.Release|x64.ActiveCfg = Release|Win32
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Debug|Win32.Build.0 = Debug|Win32
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Debug|x64.ActiveCfg = Debug|x64
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Debug|x64.Build.0 = Debug|x64
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Release|Win32.ActiveCfg = Release|Win32
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Release|Win32.Build.0 = Release|Win32
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Release|x64.ActiveCfg = Release|x64
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Release|x64.Build.0 = Release|x64
+ {EB6E138B-9DE5-41E8-A127-3675AA2BA607}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EB6E138B-9DE5-41E8-A127-3675AA2BA607}.Debug|Win32.Build.0 = Debug|Win32
+ {EB6E138B-9DE5-41E8-A127-3675AA2BA607}.Debug|x64.ActiveCfg = Debug|Win32
+ {EB6E138B-9DE5-41E8-A127-3675AA2BA607}.Release|Win32.ActiveCfg = Release|Win32
+ {EB6E138B-9DE5-41E8-A127-3675AA2BA607}.Release|Win32.Build.0 = Release|Win32
+ {EB6E138B-9DE5-41E8-A127-3675AA2BA607}.Release|x64.ActiveCfg = Release|Win32
+ {DD670DCB-2554-4FAE-B7C9-D7F0C3087C10}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DD670DCB-2554-4FAE-B7C9-D7F0C3087C10}.Debug|Win32.Build.0 = Debug|Win32
+ {DD670DCB-2554-4FAE-B7C9-D7F0C3087C10}.Debug|x64.ActiveCfg = Debug|Win32
+ {DD670DCB-2554-4FAE-B7C9-D7F0C3087C10}.Release|Win32.ActiveCfg = Release|Win32
+ {DD670DCB-2554-4FAE-B7C9-D7F0C3087C10}.Release|Win32.Build.0 = Release|Win32
+ {DD670DCB-2554-4FAE-B7C9-D7F0C3087C10}.Release|x64.ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/samples/translator/essl_to_glsl.vcproj b/samples/translator/essl_to_glsl.vcproj
new file mode 100644
index 00000000..0a0c0977
--- /dev/null
+++ b/samples/translator/essl_to_glsl.vcproj
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="essl_to_glsl"
+ ProjectGUID="{EADEBCCD-65ED-45D1-9E06-949A21EBAB9E}"
+ RootNamespace="essl_to_glsl"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\src\common\debug.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\translator.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/samples/translator/essl_to_hlsl.vcxproj b/samples/translator/essl_to_hlsl.vcxproj
new file mode 100644
index 00000000..d7bbd8cd
--- /dev/null
+++ b/samples/translator/essl_to_hlsl.vcxproj
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{E12EA115-EBC7-47C2-B651-30A0CE986025}</ProjectGuid>
+ <RootNamespace>essl_to_hlsl</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../../include;../../src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <AdditionalIncludeDirectories>../../include;../../src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\common\debug.cpp" />
+ <ClCompile Include="translator.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\src\compiler\preprocessor\preprocessor.vcxproj">
+ <Project>{fbe32df3-0fb0-4f2f-a424-2c21bd7bc325}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\src\compiler\translator_common.vcxproj">
+ <Project>{5b3a6db8-1e7e-40d7-92b9-da8aae619fad}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\src\compiler\translator_hlsl.vcxproj">
+ <Project>{5620f0e4-6c43-49bc-a178-b804e1a0c3a7}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <Private>true</Private>
+ <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/samples/translator/essl_to_hlsl.vcxproj.filters b/samples/translator/essl_to_hlsl.vcxproj.filters
new file mode 100644
index 00000000..b8a21af4
--- /dev/null
+++ b/samples/translator/essl_to_hlsl.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\common\debug.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="translator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/samples/translator/translator.cpp b/samples/translator/translator.cpp
new file mode 100644
index 00000000..98227712
--- /dev/null
+++ b/samples/translator/translator.cpp
@@ -0,0 +1,387 @@
+//
+// 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.
+//
+
+#include "GLSLANG/ShaderLang.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vector>
+
+//
+// Return codes from main.
+//
+enum TFailCode {
+ ESuccess = 0,
+ EFailUsage,
+ EFailCompile,
+ EFailCompilerCreate,
+};
+
+static void usage();
+static ShShaderType FindShaderType(const char* fileName);
+static bool CompileFile(char* fileName, ShHandle compiler, int compileOptions);
+static void LogMsg(const char* msg, const char* name, const int num, const char* logName);
+static void PrintActiveVariables(ShHandle compiler, ShShaderInfo varType, bool mapLongVariableNames);
+
+// If NUM_SOURCE_STRINGS is set to a value > 1, the input file data is
+// broken into that many chunks.
+const unsigned int NUM_SOURCE_STRINGS = 2;
+typedef std::vector<char*> ShaderSource;
+static bool ReadShaderSource(const char* fileName, ShaderSource& source);
+static void FreeShaderSource(ShaderSource& source);
+
+//
+// Set up the per compile resources
+//
+void GenerateResources(ShBuiltInResources* resources)
+{
+ ShInitBuiltInResources(resources);
+
+ resources->MaxVertexAttribs = 8;
+ resources->MaxVertexUniformVectors = 128;
+ resources->MaxVaryingVectors = 8;
+ resources->MaxVertexTextureImageUnits = 0;
+ resources->MaxCombinedTextureImageUnits = 8;
+ resources->MaxTextureImageUnits = 8;
+ resources->MaxFragmentUniformVectors = 16;
+ resources->MaxDrawBuffers = 1;
+
+ resources->OES_standard_derivatives = 0;
+ resources->OES_EGL_image_external = 0;
+}
+
+int main(int argc, char* argv[])
+{
+ TFailCode failCode = ESuccess;
+
+ int compileOptions = 0;
+ int numCompiles = 0;
+ ShHandle vertexCompiler = 0;
+ ShHandle fragmentCompiler = 0;
+ char* buffer = 0;
+ size_t bufferLen = 0;
+ int numAttribs = 0, numUniforms = 0;
+ ShShaderSpec spec = SH_GLES2_SPEC;
+ ShShaderOutput output = SH_ESSL_OUTPUT;
+
+ ShInitialize();
+
+ ShBuiltInResources resources;
+ GenerateResources(&resources);
+
+ argc--;
+ argv++;
+ for (; (argc >= 1) && (failCode == ESuccess); argc--, argv++) {
+ if (argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'i': compileOptions |= SH_INTERMEDIATE_TREE; break;
+ case 'm': compileOptions |= SH_MAP_LONG_VARIABLE_NAMES; break;
+ case 'o': compileOptions |= SH_OBJECT_CODE; break;
+ case 'u': compileOptions |= SH_ATTRIBUTES_UNIFORMS; break;
+ case 'l': compileOptions |= SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX; break;
+ case 'e': compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS; break;
+ case 'd': compileOptions |= SH_DEPENDENCY_GRAPH; break;
+ case 't': compileOptions |= SH_TIMING_RESTRICTIONS; break;
+ case 's':
+ if (argv[0][2] == '=') {
+ switch (argv[0][3]) {
+ case 'e': spec = SH_GLES2_SPEC; break;
+ case 'w': spec = SH_WEBGL_SPEC; break;
+ case 'c': spec = SH_CSS_SHADERS_SPEC; break;
+ default: failCode = EFailUsage;
+ }
+ } else {
+ failCode = EFailUsage;
+ }
+ break;
+ case 'b':
+ if (argv[0][2] == '=') {
+ switch (argv[0][3]) {
+ case 'e': output = SH_ESSL_OUTPUT; break;
+ case 'g': output = SH_GLSL_OUTPUT; break;
+ case 'h':
+ if (argv[0][4] == '1' && argv[0][5] == '1')
+ {
+ output = SH_HLSL11_OUTPUT;
+ }
+ else
+ {
+ output = SH_HLSL9_OUTPUT;
+ }
+ break;
+ default: failCode = EFailUsage;
+ }
+ } else {
+ failCode = EFailUsage;
+ }
+ break;
+ case 'x':
+ if (argv[0][2] == '=') {
+ switch (argv[0][3]) {
+ case 'i': resources.OES_EGL_image_external = 1; break;
+ case 'd': resources.OES_standard_derivatives = 1; break;
+ case 'r': resources.ARB_texture_rectangle = 1; break;
+ default: failCode = EFailUsage;
+ }
+ } else {
+ failCode = EFailUsage;
+ }
+ break;
+ default: failCode = EFailUsage;
+ }
+ } else {
+ ShHandle compiler = 0;
+ switch (FindShaderType(argv[0])) {
+ case SH_VERTEX_SHADER:
+ if (vertexCompiler == 0)
+ vertexCompiler = ShConstructCompiler(
+ SH_VERTEX_SHADER, spec, output, &resources);
+ compiler = vertexCompiler;
+ break;
+ case SH_FRAGMENT_SHADER:
+ if (fragmentCompiler == 0)
+ fragmentCompiler = ShConstructCompiler(
+ SH_FRAGMENT_SHADER, spec, output, &resources);
+ compiler = fragmentCompiler;
+ break;
+ default: break;
+ }
+ if (compiler) {
+ bool compiled = CompileFile(argv[0], compiler, compileOptions);
+
+ LogMsg("BEGIN", "COMPILER", numCompiles, "INFO LOG");
+ ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &bufferLen);
+ buffer = (char*) realloc(buffer, bufferLen * sizeof(char));
+ ShGetInfoLog(compiler, buffer);
+ puts(buffer);
+ LogMsg("END", "COMPILER", numCompiles, "INFO LOG");
+ printf("\n\n");
+
+ if (compiled && (compileOptions & SH_OBJECT_CODE)) {
+ LogMsg("BEGIN", "COMPILER", numCompiles, "OBJ CODE");
+ ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &bufferLen);
+ buffer = (char*) realloc(buffer, bufferLen * sizeof(char));
+ ShGetObjectCode(compiler, buffer);
+ puts(buffer);
+ LogMsg("END", "COMPILER", numCompiles, "OBJ CODE");
+ printf("\n\n");
+ }
+ if (compiled && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) {
+ LogMsg("BEGIN", "COMPILER", numCompiles, "ACTIVE ATTRIBS");
+ PrintActiveVariables(compiler, SH_ACTIVE_ATTRIBUTES, (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) != 0);
+ LogMsg("END", "COMPILER", numCompiles, "ACTIVE ATTRIBS");
+ printf("\n\n");
+
+ LogMsg("BEGIN", "COMPILER", numCompiles, "ACTIVE UNIFORMS");
+ PrintActiveVariables(compiler, SH_ACTIVE_UNIFORMS, (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) != 0);
+ LogMsg("END", "COMPILER", numCompiles, "ACTIVE UNIFORMS");
+ printf("\n\n");
+ }
+ if (!compiled)
+ failCode = EFailCompile;
+ ++numCompiles;
+ } else {
+ failCode = EFailCompilerCreate;
+ }
+ }
+ }
+
+ if ((vertexCompiler == 0) && (fragmentCompiler == 0))
+ failCode = EFailUsage;
+ if (failCode == EFailUsage)
+ usage();
+
+ if (vertexCompiler)
+ ShDestruct(vertexCompiler);
+ if (fragmentCompiler)
+ ShDestruct(fragmentCompiler);
+ if (buffer)
+ free(buffer);
+ ShFinalize();
+
+ return failCode;
+}
+
+//
+// print usage to stdout
+//
+void usage()
+{
+ printf("Usage: translate [-i -m -o -u -l -e -b=e -b=g -b=h -x=i -x=d] file1 file2 ...\n"
+ "Where: filename : filename ending in .frag or .vert\n"
+ " -i : print intermediate tree\n"
+ " -m : map long variable names\n"
+ " -o : print translated code\n"
+ " -u : print active attribs and uniforms\n"
+ " -l : unroll for-loops with integer indices\n"
+ " -e : emulate certain built-in functions (workaround for driver bugs)\n"
+ " -t : enforce experimental timing restrictions\n"
+ " -d : print dependency graph used to enforce timing restrictions\n"
+ " -s=e : use GLES2 spec (this is by default)\n"
+ " -s=w : use WebGL spec\n"
+ " -s=c : use CSS Shaders spec\n"
+ " -b=e : output GLSL ES code (this is by default)\n"
+ " -b=g : output GLSL code\n"
+ " -b=h9 : output HLSL9 code\n"
+ " -b=h11 : output HLSL11 code\n"
+ " -x=i : enable GL_OES_EGL_image_external\n"
+ " -x=d : enable GL_OES_EGL_standard_derivatives\n"
+ " -x=r : enable ARB_texture_rectangle\n");
+}
+
+//
+// Deduce the shader type from the filename. Files must end in one of the
+// following extensions:
+//
+// .frag* = fragment shader
+// .vert* = vertex shader
+//
+ShShaderType FindShaderType(const char* fileName)
+{
+ assert(fileName);
+
+ const char* ext = strrchr(fileName, '.');
+
+ if (ext && strcmp(ext, ".sl") == 0)
+ for (; ext > fileName && ext[0] != '.'; ext--);
+
+ ext = strrchr(fileName, '.');
+ if (ext) {
+ if (strncmp(ext, ".frag", 4) == 0) return SH_FRAGMENT_SHADER;
+ if (strncmp(ext, ".vert", 4) == 0) return SH_VERTEX_SHADER;
+ }
+
+ return SH_FRAGMENT_SHADER;
+}
+
+//
+// Read a file's data into a string, and compile it using ShCompile
+//
+bool CompileFile(char* fileName, ShHandle compiler, int compileOptions)
+{
+ ShaderSource source;
+ if (!ReadShaderSource(fileName, source))
+ return false;
+
+ int ret = ShCompile(compiler, &source[0], source.size(), compileOptions);
+
+ FreeShaderSource(source);
+ return ret ? true : false;
+}
+
+void LogMsg(const char* msg, const char* name, const int num, const char* logName)
+{
+ printf("#### %s %s %d %s ####\n", msg, name, num, logName);
+}
+
+void PrintActiveVariables(ShHandle compiler, ShShaderInfo varType, bool mapLongVariableNames)
+{
+ size_t nameSize = 0;
+ switch (varType) {
+ case SH_ACTIVE_ATTRIBUTES:
+ ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &nameSize);
+ break;
+ case SH_ACTIVE_UNIFORMS:
+ ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &nameSize);
+ break;
+ default: assert(0);
+ }
+ if (nameSize <= 1) return;
+ char* name = new char[nameSize];
+
+ char* mappedName = NULL;
+ if (mapLongVariableNames) {
+ size_t mappedNameSize = 0;
+ ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameSize);
+ mappedName = new char[mappedNameSize];
+ }
+
+ size_t activeVars = 0;
+ int size = 0;
+ ShDataType type = SH_NONE;
+ const char* typeName = NULL;
+ ShGetInfo(compiler, varType, &activeVars);
+ for (size_t i = 0; i < activeVars; ++i) {
+ switch (varType) {
+ case SH_ACTIVE_ATTRIBUTES:
+ ShGetActiveAttrib(compiler, static_cast<int>(i), NULL, &size, &type, name, mappedName);
+ break;
+ case SH_ACTIVE_UNIFORMS:
+ ShGetActiveUniform(compiler, static_cast<int>(i), NULL, &size, &type, name, mappedName);
+ break;
+ default: assert(0);
+ }
+ switch (type) {
+ case SH_FLOAT: typeName = "GL_FLOAT"; break;
+ case SH_FLOAT_VEC2: typeName = "GL_FLOAT_VEC2"; break;
+ case SH_FLOAT_VEC3: typeName = "GL_FLOAT_VEC3"; break;
+ case SH_FLOAT_VEC4: typeName = "GL_FLOAT_VEC4"; break;
+ case SH_INT: typeName = "GL_INT"; break;
+ case SH_INT_VEC2: typeName = "GL_INT_VEC2"; break;
+ case SH_INT_VEC3: typeName = "GL_INT_VEC3"; break;
+ case SH_INT_VEC4: typeName = "GL_INT_VEC4"; break;
+ case SH_BOOL: typeName = "GL_BOOL"; break;
+ case SH_BOOL_VEC2: typeName = "GL_BOOL_VEC2"; break;
+ case SH_BOOL_VEC3: typeName = "GL_BOOL_VEC3"; break;
+ case SH_BOOL_VEC4: typeName = "GL_BOOL_VEC4"; break;
+ case SH_FLOAT_MAT2: typeName = "GL_FLOAT_MAT2"; break;
+ case SH_FLOAT_MAT3: typeName = "GL_FLOAT_MAT3"; break;
+ case SH_FLOAT_MAT4: typeName = "GL_FLOAT_MAT4"; break;
+ case SH_SAMPLER_2D: typeName = "GL_SAMPLER_2D"; break;
+ case SH_SAMPLER_CUBE: typeName = "GL_SAMPLER_CUBE"; break;
+ case SH_SAMPLER_EXTERNAL_OES: typeName = "GL_SAMPLER_EXTERNAL_OES"; break;
+ default: assert(0);
+ }
+ printf("%u: name:%s type:%s size:%d", i, name, typeName, size);
+ if (mapLongVariableNames)
+ printf(" mapped name:%s", mappedName);
+ printf("\n");
+ }
+ delete [] name;
+ if (mappedName)
+ delete [] mappedName;
+}
+
+static bool ReadShaderSource(const char* fileName, ShaderSource& source) {
+ FILE* in = fopen(fileName, "rb");
+ if (!in) {
+ printf("Error: unable to open input file: %s\n", fileName);
+ return false;
+ }
+
+ // Obtain file size.
+ fseek(in, 0, SEEK_END);
+ int count = ftell(in);
+ rewind(in);
+
+ int len = (int)ceil((float)count / (float)NUM_SOURCE_STRINGS);
+ source.reserve(NUM_SOURCE_STRINGS);
+ // Notice the usage of do-while instead of a while loop here.
+ // It is there to handle empty files in which case a single empty
+ // string is added to vector.
+ do {
+ char* data = new char[len + 1];
+ int nread = fread(data, 1, len, in);
+ data[nread] = '\0';
+ source.push_back(data);
+
+ count -= nread;
+ } while (count > 0);
+
+ fclose(in);
+ return true;
+}
+
+static void FreeShaderSource(ShaderSource& source) {
+ for (ShaderSource::size_type i = 0; i < source.size(); ++i) {
+ delete [] source[i];
+ }
+ source.clear();
+}
+
diff --git a/src/ANGLE.sln b/src/ANGLE.sln
new file mode 100644
index 00000000..81c1382f
--- /dev/null
+++ b/src/ANGLE.sln
@@ -0,0 +1,66 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libEGL", "libEGL\libEGL.vcxproj", "{E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libGLESv2", "libGLESv2\libGLESv2.vcxproj", "{B5871A7A-968C-42E3-A33B-981E6F448E78}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "translator_hlsl", "compiler\translator_hlsl.vcxproj", "{5620F0E4-6C43-49BC-A178-B804E1A0C3A7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "translator_common", "compiler\translator_common.vcxproj", "{5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "preprocessor", "compiler\preprocessor\preprocessor.vcxproj", "{FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|Win32.Build.0 = Debug|Win32
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|x64.ActiveCfg = Debug|x64
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|x64.Build.0 = Debug|x64
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|Win32.ActiveCfg = Release|Win32
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|Win32.Build.0 = Release|Win32
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|x64.ActiveCfg = Release|x64
+ {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|x64.Build.0 = Release|x64
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|Win32.Build.0 = Debug|Win32
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|x64.ActiveCfg = Debug|x64
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|x64.Build.0 = Debug|x64
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|Win32.ActiveCfg = Release|Win32
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|Win32.Build.0 = Release|Win32
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|x64.ActiveCfg = Release|x64
+ {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|x64.Build.0 = Release|x64
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Debug|Win32.Build.0 = Debug|Win32
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Debug|x64.ActiveCfg = Debug|x64
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Debug|x64.Build.0 = Debug|x64
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Release|Win32.ActiveCfg = Release|Win32
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Release|Win32.Build.0 = Release|Win32
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Release|x64.ActiveCfg = Release|x64
+ {5620F0E4-6C43-49BC-A178-B804E1A0C3A7}.Release|x64.Build.0 = Release|x64
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|Win32.Build.0 = Debug|Win32
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|x64.ActiveCfg = Debug|x64
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|x64.Build.0 = Debug|x64
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|Win32.ActiveCfg = Release|Win32
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|Win32.Build.0 = Release|Win32
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|x64.ActiveCfg = Release|x64
+ {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|x64.Build.0 = Release|x64
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Debug|Win32.Build.0 = Debug|Win32
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Debug|x64.ActiveCfg = Debug|x64
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Debug|x64.Build.0 = Debug|x64
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Release|Win32.ActiveCfg = Release|Win32
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Release|Win32.Build.0 = Release|Win32
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Release|x64.ActiveCfg = Release|x64
+ {FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/build_angle.gyp b/src/build_angle.gyp
new file mode 100644
index 00000000..6adf1423
--- /dev/null
+++ b/src/build_angle.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ 'build_angle.gypi',
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/src/build_angle.gypi b/src/build_angle.gypi
new file mode 100644
index 00000000..c91cce1b
--- /dev/null
+++ b/src/build_angle.gypi
@@ -0,0 +1,422 @@
+# Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'angle_code': 1,
+ },
+ 'target_defaults': {
+ 'defines': [
+ 'ANGLE_DISABLE_TRACE',
+ 'ANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1',
+ 'ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }',
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'preprocessor',
+ 'type': 'static_library',
+ 'include_dirs': [
+ ],
+ 'sources': [
+ 'compiler/preprocessor/DiagnosticsBase.cpp',
+ 'compiler/preprocessor/DiagnosticsBase.h',
+ 'compiler/preprocessor/DirectiveHandlerBase.cpp',
+ 'compiler/preprocessor/DirectiveHandlerBase.h',
+ 'compiler/preprocessor/DirectiveParser.cpp',
+ 'compiler/preprocessor/DirectiveParser.h',
+ 'compiler/preprocessor/ExpressionParser.cpp',
+ 'compiler/preprocessor/ExpressionParser.h',
+ 'compiler/preprocessor/Input.cpp',
+ 'compiler/preprocessor/Input.h',
+ 'compiler/preprocessor/length_limits.h',
+ 'compiler/preprocessor/Lexer.cpp',
+ 'compiler/preprocessor/Lexer.h',
+ 'compiler/preprocessor/Macro.cpp',
+ 'compiler/preprocessor/Macro.h',
+ 'compiler/preprocessor/MacroExpander.cpp',
+ 'compiler/preprocessor/MacroExpander.h',
+ 'compiler/preprocessor/numeric_lex.h',
+ 'compiler/preprocessor/pp_utils.h',
+ 'compiler/preprocessor/Preprocessor.cpp',
+ 'compiler/preprocessor/Preprocessor.h',
+ 'compiler/preprocessor/SourceLocation.h',
+ 'compiler/preprocessor/Token.cpp',
+ 'compiler/preprocessor/Token.h',
+ 'compiler/preprocessor/Tokenizer.cpp',
+ 'compiler/preprocessor/Tokenizer.h',
+ ],
+ # TODO(jschuh): http://crbug.com/167187
+ 'msvs_disabled_warnings': [
+ 4267,
+ ],
+ },
+ {
+ 'target_name': 'translator_common',
+ 'type': 'static_library',
+ 'dependencies': ['preprocessor'],
+ 'include_dirs': [
+ '.',
+ '../include',
+ ],
+ 'defines': [
+ 'COMPILER_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'compiler/BaseTypes.h',
+ 'compiler/BuiltInFunctionEmulator.cpp',
+ 'compiler/BuiltInFunctionEmulator.h',
+ 'compiler/Common.h',
+ 'compiler/Compiler.cpp',
+ 'compiler/ConstantUnion.h',
+ 'compiler/debug.cpp',
+ 'compiler/debug.h',
+ 'compiler/DetectCallDepth.cpp',
+ 'compiler/DetectCallDepth.h',
+ 'compiler/Diagnostics.h',
+ 'compiler/Diagnostics.cpp',
+ 'compiler/DirectiveHandler.h',
+ 'compiler/DirectiveHandler.cpp',
+ 'compiler/ExtensionBehavior.h',
+ 'compiler/ForLoopUnroll.cpp',
+ 'compiler/ForLoopUnroll.h',
+ 'compiler/glslang.h',
+ 'compiler/glslang_lex.cpp',
+ 'compiler/glslang_tab.cpp',
+ 'compiler/glslang_tab.h',
+ 'compiler/HashNames.h',
+ 'compiler/InfoSink.cpp',
+ 'compiler/InfoSink.h',
+ 'compiler/Initialize.cpp',
+ 'compiler/Initialize.h',
+ 'compiler/InitializeDll.cpp',
+ 'compiler/InitializeDll.h',
+ 'compiler/InitializeGlobals.h',
+ 'compiler/InitializeParseContext.cpp',
+ 'compiler/InitializeParseContext.h',
+ 'compiler/Intermediate.cpp',
+ 'compiler/intermediate.h',
+ 'compiler/intermOut.cpp',
+ 'compiler/IntermTraverse.cpp',
+ 'compiler/localintermediate.h',
+ 'compiler/MapLongVariableNames.cpp',
+ 'compiler/MapLongVariableNames.h',
+ 'compiler/MMap.h',
+ 'compiler/osinclude.h',
+ 'compiler/parseConst.cpp',
+ 'compiler/ParseHelper.cpp',
+ 'compiler/ParseHelper.h',
+ 'compiler/PoolAlloc.cpp',
+ 'compiler/PoolAlloc.h',
+ 'compiler/QualifierAlive.cpp',
+ 'compiler/QualifierAlive.h',
+ 'compiler/RemoveTree.cpp',
+ 'compiler/RemoveTree.h',
+ 'compiler/RenameFunction.h',
+ 'compiler/ShHandle.h',
+ 'compiler/SymbolTable.cpp',
+ 'compiler/SymbolTable.h',
+ 'compiler/Types.h',
+ 'compiler/Uniform.cpp',
+ 'compiler/Uniform.h',
+ 'compiler/util.cpp',
+ 'compiler/util.h',
+ 'compiler/ValidateLimitations.cpp',
+ 'compiler/ValidateLimitations.h',
+ 'compiler/VariableInfo.cpp',
+ 'compiler/VariableInfo.h',
+ 'compiler/VariablePacker.cpp',
+ 'compiler/VariablePacker.h',
+ # Dependency graph
+ 'compiler/depgraph/DependencyGraph.cpp',
+ 'compiler/depgraph/DependencyGraph.h',
+ 'compiler/depgraph/DependencyGraphBuilder.cpp',
+ 'compiler/depgraph/DependencyGraphBuilder.h',
+ 'compiler/depgraph/DependencyGraphOutput.cpp',
+ 'compiler/depgraph/DependencyGraphOutput.h',
+ 'compiler/depgraph/DependencyGraphTraverse.cpp',
+ # Timing restrictions
+ 'compiler/timing/RestrictFragmentShaderTiming.cpp',
+ 'compiler/timing/RestrictFragmentShaderTiming.h',
+ 'compiler/timing/RestrictVertexShaderTiming.cpp',
+ 'compiler/timing/RestrictVertexShaderTiming.h',
+ 'third_party/compiler/ArrayBoundsClamper.cpp',
+ 'third_party/compiler/ArrayBoundsClamper.h',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ # TODO(jschuh): http://crbug.com/167187 size_t -> int
+ 'msvs_disabled_warnings': [ 4267 ],
+ 'sources': ['compiler/ossource_win.cpp'],
+ }, { # else: posix
+ 'sources': ['compiler/ossource_posix.cpp'],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'translator_glsl',
+ 'type': '<(component)',
+ 'dependencies': ['translator_common'],
+ 'include_dirs': [
+ '.',
+ '../include',
+ ],
+ 'defines': [
+ 'COMPILER_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'compiler/CodeGenGLSL.cpp',
+ 'compiler/OutputESSL.cpp',
+ 'compiler/OutputESSL.h',
+ 'compiler/OutputGLSLBase.cpp',
+ 'compiler/OutputGLSLBase.h',
+ 'compiler/OutputGLSL.cpp',
+ 'compiler/OutputGLSL.h',
+ 'compiler/ShaderLang.cpp',
+ 'compiler/TranslatorESSL.cpp',
+ 'compiler/TranslatorESSL.h',
+ 'compiler/TranslatorGLSL.cpp',
+ 'compiler/TranslatorGLSL.h',
+ 'compiler/VersionGLSL.cpp',
+ 'compiler/VersionGLSL.h',
+ ],
+ # TODO(jschuh): http://crbug.com/167187 size_t -> int
+ 'msvs_disabled_warnings': [ 4267 ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'targets': [
+ {
+ 'target_name': 'translator_hlsl',
+ 'type': '<(component)',
+ 'dependencies': ['translator_common'],
+ 'include_dirs': [
+ '.',
+ '../include',
+ ],
+ 'defines': [
+ 'COMPILER_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'compiler/ShaderLang.cpp',
+ 'compiler/DetectDiscontinuity.cpp',
+ 'compiler/DetectDiscontinuity.h',
+ 'compiler/CodeGenHLSL.cpp',
+ 'compiler/OutputHLSL.cpp',
+ 'compiler/OutputHLSL.h',
+ 'compiler/TranslatorHLSL.cpp',
+ 'compiler/TranslatorHLSL.h',
+ 'compiler/UnfoldShortCircuit.cpp',
+ 'compiler/UnfoldShortCircuit.h',
+ 'compiler/SearchSymbol.cpp',
+ 'compiler/SearchSymbol.h',
+ ],
+ # TODO(jschuh): http://crbug.com/167187 size_t -> int
+ 'msvs_disabled_warnings': [ 4267 ],
+ },
+ {
+ 'target_name': 'libGLESv2',
+ 'type': 'shared_library',
+ 'dependencies': ['translator_hlsl'],
+ 'include_dirs': [
+ '.',
+ '../include',
+ 'libGLESv2',
+ ],
+ 'sources': [
+ 'third_party/murmurhash/MurmurHash3.h',
+ 'third_party/murmurhash/MurmurHash3.cpp',
+ 'common/angleutils.h',
+ 'common/debug.cpp',
+ 'common/debug.h',
+ 'common/RefCountObject.cpp',
+ 'common/RefCountObject.h',
+ 'common/version.h',
+ 'libGLESv2/precompiled.h',
+ 'libGLESv2/precompiled.cpp',
+ 'libGLESv2/BinaryStream.h',
+ 'libGLESv2/Buffer.cpp',
+ 'libGLESv2/Buffer.h',
+ 'libGLESv2/constants.h',
+ 'libGLESv2/Context.cpp',
+ 'libGLESv2/Context.h',
+ 'libGLESv2/angletypes.h',
+ 'libGLESv2/Fence.cpp',
+ 'libGLESv2/Fence.h',
+ 'libGLESv2/Float16ToFloat32.cpp',
+ 'libGLESv2/Framebuffer.cpp',
+ 'libGLESv2/Framebuffer.h',
+ 'libGLESv2/HandleAllocator.cpp',
+ 'libGLESv2/HandleAllocator.h',
+ 'libGLESv2/libGLESv2.cpp',
+ 'libGLESv2/libGLESv2.def',
+ 'libGLESv2/libGLESv2.rc',
+ 'libGLESv2/main.cpp',
+ 'libGLESv2/main.h',
+ 'libGLESv2/mathutil.h',
+ 'libGLESv2/Program.cpp',
+ 'libGLESv2/Program.h',
+ 'libGLESv2/ProgramBinary.cpp',
+ 'libGLESv2/ProgramBinary.h',
+ 'libGLESv2/Query.h',
+ 'libGLESv2/Query.cpp',
+ 'libGLESv2/Renderbuffer.cpp',
+ 'libGLESv2/Renderbuffer.h',
+ 'libGLESv2/renderer/Blit.cpp',
+ 'libGLESv2/renderer/Blit.h',
+ 'libGLESv2/renderer/BufferStorage.h',
+ 'libGLESv2/renderer/BufferStorage.cpp',
+ 'libGLESv2/renderer/BufferStorage9.cpp',
+ 'libGLESv2/renderer/BufferStorage9.h',
+ 'libGLESv2/renderer/BufferStorage11.cpp',
+ 'libGLESv2/renderer/BufferStorage11.h',
+ 'libGLESv2/renderer/FenceImpl.h',
+ 'libGLESv2/renderer/Fence9.cpp',
+ 'libGLESv2/renderer/Fence9.h',
+ 'libGLESv2/renderer/Fence11.cpp',
+ 'libGLESv2/renderer/Fence11.h',
+ 'libGLESv2/renderer/generatemip.h',
+ 'libGLESv2/renderer/Image.cpp',
+ 'libGLESv2/renderer/Image.h',
+ 'libGLESv2/renderer/Image11.cpp',
+ 'libGLESv2/renderer/Image11.h',
+ 'libGLESv2/renderer/Image9.cpp',
+ 'libGLESv2/renderer/Image9.h',
+ 'libGLESv2/renderer/ImageSSE2.cpp',
+ 'libGLESv2/renderer/IndexBuffer.cpp',
+ 'libGLESv2/renderer/IndexBuffer.h',
+ 'libGLESv2/renderer/IndexBuffer9.cpp',
+ 'libGLESv2/renderer/IndexBuffer9.h',
+ 'libGLESv2/renderer/IndexBuffer11.cpp',
+ 'libGLESv2/renderer/IndexBuffer11.h',
+ 'libGLESv2/renderer/IndexDataManager.cpp',
+ 'libGLESv2/renderer/IndexDataManager.h',
+ 'libGLESv2/renderer/IndexRangeCache.cpp',
+ 'libGLESv2/renderer/IndexRangeCache.h',
+ 'libGLESv2/renderer/InputLayoutCache.cpp',
+ 'libGLESv2/renderer/InputLayoutCache.h',
+ 'libGLESv2/renderer/QueryImpl.h',
+ 'libGLESv2/renderer/Query9.cpp',
+ 'libGLESv2/renderer/Query9.h',
+ 'libGLESv2/renderer/Query11.cpp',
+ 'libGLESv2/renderer/Query11.h',
+ 'libGLESv2/renderer/Renderer.cpp',
+ 'libGLESv2/renderer/Renderer.h',
+ 'libGLESv2/renderer/Renderer11.cpp',
+ 'libGLESv2/renderer/Renderer11.h',
+ 'libGLESv2/renderer/renderer11_utils.cpp',
+ 'libGLESv2/renderer/renderer11_utils.h',
+ 'libGLESv2/renderer/Renderer9.cpp',
+ 'libGLESv2/renderer/Renderer9.h',
+ 'libGLESv2/renderer/renderer9_utils.cpp',
+ 'libGLESv2/renderer/renderer9_utils.h',
+ 'libGLESv2/renderer/RenderStateCache.cpp',
+ 'libGLESv2/renderer/RenderStateCache.h',
+ 'libGLESv2/renderer/RenderTarget.h',
+ 'libGLESv2/renderer/RenderTarget11.h',
+ 'libGLESv2/renderer/RenderTarget11.cpp',
+ 'libGLESv2/renderer/RenderTarget9.h',
+ 'libGLESv2/renderer/RenderTarget9.cpp',
+ 'libGLESv2/renderer/ShaderCache.h',
+ 'libGLESv2/renderer/ShaderExecutable.h',
+ 'libGLESv2/renderer/ShaderExecutable9.cpp',
+ 'libGLESv2/renderer/ShaderExecutable9.h',
+ 'libGLESv2/renderer/ShaderExecutable11.cpp',
+ 'libGLESv2/renderer/ShaderExecutable11.h',
+ 'libGLESv2/renderer/SwapChain.h',
+ 'libGLESv2/renderer/SwapChain9.cpp',
+ 'libGLESv2/renderer/SwapChain9.h',
+ 'libGLESv2/renderer/SwapChain11.cpp',
+ 'libGLESv2/renderer/SwapChain11.h',
+ 'libGLESv2/renderer/TextureStorage.cpp',
+ 'libGLESv2/renderer/TextureStorage.h',
+ 'libGLESv2/renderer/TextureStorage11.cpp',
+ 'libGLESv2/renderer/TextureStorage11.h',
+ 'libGLESv2/renderer/TextureStorage9.cpp',
+ 'libGLESv2/renderer/TextureStorage9.h',
+ 'libGLESv2/renderer/VertexBuffer.cpp',
+ 'libGLESv2/renderer/VertexBuffer.h',
+ 'libGLESv2/renderer/VertexBuffer9.cpp',
+ 'libGLESv2/renderer/VertexBuffer9.h',
+ 'libGLESv2/renderer/VertexBuffer11.cpp',
+ 'libGLESv2/renderer/VertexBuffer11.h',
+ 'libGLESv2/renderer/vertexconversion.h',
+ 'libGLESv2/renderer/VertexDataManager.cpp',
+ 'libGLESv2/renderer/VertexDataManager.h',
+ 'libGLESv2/renderer/VertexDeclarationCache.cpp',
+ 'libGLESv2/renderer/VertexDeclarationCache.h',
+ 'libGLESv2/ResourceManager.cpp',
+ 'libGLESv2/ResourceManager.h',
+ 'libGLESv2/Shader.cpp',
+ 'libGLESv2/Shader.h',
+ 'libGLESv2/Texture.cpp',
+ 'libGLESv2/Texture.h',
+ 'libGLESv2/Uniform.cpp',
+ 'libGLESv2/Uniform.h',
+ 'libGLESv2/utilities.cpp',
+ 'libGLESv2/utilities.h',
+ ],
+ # TODO(jschuh): http://crbug.com/167187 size_t -> int
+ 'msvs_disabled_warnings': [ 4267 ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [
+ 'd3d9.lib',
+ 'dxguid.lib',
+ ],
+ }
+ },
+ },
+ {
+ 'target_name': 'libEGL',
+ 'type': 'shared_library',
+ 'dependencies': ['libGLESv2'],
+ 'include_dirs': [
+ '.',
+ '../include',
+ 'libGLESv2',
+ ],
+ 'sources': [
+ 'common/angleutils.h',
+ 'common/debug.cpp',
+ 'common/debug.h',
+ 'common/RefCountObject.cpp',
+ 'common/RefCountObject.h',
+ 'common/version.h',
+ 'libEGL/Config.cpp',
+ 'libEGL/Config.h',
+ 'libEGL/Display.cpp',
+ 'libEGL/Display.h',
+ 'libEGL/libEGL.cpp',
+ 'libEGL/libEGL.def',
+ 'libEGL/libEGL.rc',
+ 'libEGL/main.cpp',
+ 'libEGL/main.h',
+ 'libEGL/Surface.cpp',
+ 'libEGL/Surface.h',
+ ],
+ # TODO(jschuh): http://crbug.com/167187 size_t -> int
+ 'msvs_disabled_warnings': [ 4267 ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [
+ 'd3d9.lib',
+ ],
+ }
+ },
+ },
+ ],
+ }],
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
+# Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/src/common/RefCountObject.cpp b/src/common/RefCountObject.cpp
new file mode 100644
index 00000000..0364adf2
--- /dev/null
+++ b/src/common/RefCountObject.cpp
@@ -0,0 +1,48 @@
+#include "precompiled.h"
+//
+// 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;
+ }
+}
+
+void RefCountObjectBindingPointer::set(RefCountObject *newObject)
+{
+ // addRef first in case newObject == mObject and this is the last reference to it.
+ if (newObject != NULL) newObject->addRef();
+ if (mObject != NULL) mObject->release();
+
+ mObject = newObject;
+}
diff --git a/src/common/RefCountObject.h b/src/common/RefCountObject.h
new file mode 100644
index 00000000..727c71c3
--- /dev/null
+++ b/src/common/RefCountObject.h
@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RefCountObject.h: Defines the gl::RefCountObject base class that provides
+// lifecycle support for GL objects using the traditional BindObject scheme, but
+// that need to be reference counted for correct cross-context deletion.
+// (Concretely, textures, buffers and renderbuffers.)
+
+#ifndef COMMON_REFCOUNTOBJECT_H_
+#define COMMON_REFCOUNTOBJECT_H_
+
+#include <cstddef>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "common/debug.h"
+
+class RefCountObject
+{
+ public:
+ explicit RefCountObject(GLuint id);
+ virtual ~RefCountObject();
+
+ virtual void addRef() const;
+ virtual void release() const;
+
+ GLuint id() const { return mId; }
+
+ private:
+ GLuint mId;
+
+ mutable std::size_t mRefCount;
+};
+
+class RefCountObjectBindingPointer
+{
+ protected:
+ RefCountObjectBindingPointer() : mObject(NULL) { }
+ ~RefCountObjectBindingPointer() { ASSERT(mObject == NULL); } // Objects have to be released before the resource manager is destroyed, so they must be explicitly cleaned up.
+
+ void set(RefCountObject *newObject);
+ RefCountObject *get() const { return mObject; }
+
+ public:
+ GLuint id() const { return (mObject != NULL) ? mObject->id() : 0; }
+ bool operator ! () const { return (get() == NULL); }
+
+ private:
+ RefCountObject *mObject;
+};
+
+template <class ObjectType>
+class BindingPointer : public RefCountObjectBindingPointer
+{
+ public:
+ void set(ObjectType *newObject) { RefCountObjectBindingPointer::set(newObject); }
+ ObjectType *get() const { return static_cast<ObjectType*>(RefCountObjectBindingPointer::get()); }
+ ObjectType *operator -> () const { return get(); }
+};
+
+#endif // COMMON_REFCOUNTOBJECT_H_
diff --git a/src/common/angleutils.h b/src/common/angleutils.h
new file mode 100644
index 00000000..9761567f
--- /dev/null
+++ b/src/common/angleutils.h
@@ -0,0 +1,56 @@
+//
+// 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.
+//
+
+// angleutils.h: Common ANGLE utilities.
+
+#ifndef COMMON_ANGLEUTILS_H_
+#define COMMON_ANGLEUTILS_H_
+
+#include <stddef.h>
+
+// A macro to disallow the copy constructor and operator= functions
+// This must be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+template <typename T, unsigned int N>
+inline unsigned int ArraySize(T(&)[N])
+{
+ return N;
+}
+
+template <typename T, unsigned int N>
+void SafeRelease(T (&resourceBlock)[N])
+{
+ for (unsigned int i = 0; i < N; i++)
+ {
+ SafeRelease(resourceBlock[i]);
+ }
+}
+
+template <typename T>
+void SafeRelease(T& resource)
+{
+ if (resource)
+ {
+ resource->Release();
+ resource = NULL;
+ }
+}
+
+#if defined(_MSC_VER)
+#define snprintf _snprintf
+#endif
+
+#define VENDOR_ID_AMD 0x1002
+#define VENDOR_ID_INTEL 0x8086
+#define VENDOR_ID_NVIDIA 0x10DE
+
+#define GL_BGRA4_ANGLEX 0x6ABC
+#define GL_BGR5_A1_ANGLEX 0x6ABD
+
+#endif // COMMON_ANGLEUTILS_H_
diff --git a/src/common/debug.cpp b/src/common/debug.cpp
new file mode 100644
index 00000000..23337405
--- /dev/null
+++ b/src/common/debug.cpp
@@ -0,0 +1,106 @@
+//
+// 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.
+//
+
+// debug.cpp: Debugging utilities.
+
+#include "common/debug.h"
+#include "common/system.h"
+#include <d3d9.h>
+
+namespace gl
+{
+
+typedef void (WINAPI *PerfOutputFunction)(D3DCOLOR, LPCWSTR);
+
+static void output(bool traceFileDebugOnly, PerfOutputFunction perfFunc, const char *format, va_list vararg)
+{
+#if !defined(ANGLE_DISABLE_PERF)
+ if (perfActive())
+ {
+ char message[32768];
+ int len = vsprintf_s(message, format, vararg);
+ if (len < 0)
+ {
+ return;
+ }
+
+ // There are no ASCII variants of these D3DPERF functions.
+ wchar_t wideMessage[32768];
+ for (int i = 0; i < len; ++i)
+ {
+ wideMessage[i] = message[i];
+ }
+ wideMessage[len] = 0;
+
+ perfFunc(0, wideMessage);
+ }
+#endif
+
+#if !defined(ANGLE_DISABLE_TRACE)
+#if defined(NDEBUG)
+ if (traceFileDebugOnly)
+ {
+ return;
+ }
+#endif
+
+ FILE* file = fopen(TRACE_OUTPUT_FILE, "a");
+ if (file)
+ {
+ vfprintf(file, format, vararg);
+ fclose(file);
+ }
+#endif
+}
+
+void trace(bool traceFileDebugOnly, const char *format, ...)
+{
+ va_list vararg;
+ va_start(vararg, format);
+#if defined(ANGLE_DISABLE_PERF)
+ output(traceFileDebugOnly, NULL, format, vararg);
+#else
+ output(traceFileDebugOnly, D3DPERF_SetMarker, format, vararg);
+#endif
+ va_end(vararg);
+}
+
+bool perfActive()
+{
+#if defined(ANGLE_DISABLE_PERF)
+ return false;
+#else
+ static bool active = D3DPERF_GetStatus() != 0;
+ return active;
+#endif
+}
+
+ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...)
+{
+#if !defined(ANGLE_DISABLE_PERF)
+#if defined(ANGLE_DISABLE_TRACE)
+ if (!perfActive())
+ {
+ return;
+ }
+#endif
+ va_list vararg;
+ va_start(vararg, format);
+ output(true, reinterpret_cast<PerfOutputFunction>(D3DPERF_BeginEvent), format, vararg);
+ va_end(vararg);
+#endif
+}
+
+ScopedPerfEventHelper::~ScopedPerfEventHelper()
+{
+#if !defined(ANGLE_DISABLE_PERF)
+ if (perfActive())
+ {
+ D3DPERF_EndEvent();
+ }
+#endif
+}
+}
diff --git a/src/common/debug.h b/src/common/debug.h
new file mode 100644
index 00000000..23ee26d2
--- /dev/null
+++ b/src/common/debug.h
@@ -0,0 +1,112 @@
+//
+// 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.
+//
+
+// debug.h: Debugging utilities.
+
+#ifndef COMMON_DEBUG_H_
+#define COMMON_DEBUG_H_
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "common/angleutils.h"
+
+#if !defined(TRACE_OUTPUT_FILE)
+#define TRACE_OUTPUT_FILE "debug.txt"
+#endif
+
+namespace gl
+{
+ // Outputs text to the debugging log
+ void trace(bool traceFileDebugOnly, const char *format, ...);
+
+ // Returns whether D3DPERF is active.
+ bool perfActive();
+
+ // Pairs a D3D begin event with an end event.
+ class ScopedPerfEventHelper
+ {
+ public:
+ ScopedPerfEventHelper(const char* format, ...);
+ ~ScopedPerfEventHelper();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedPerfEventHelper);
+ };
+}
+
+// A macro to output a trace of a function call and its arguments to the debugging log
+#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF)
+#define TRACE(message, ...) (void(0))
+#else
+#define TRACE(message, ...) gl::trace(true, "trace: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#endif
+
+// A macro to output a function call and its arguments to the debugging log, to denote an item in need of fixing.
+#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF)
+#define FIXME(message, ...) (void(0))
+#else
+#define FIXME(message, ...) gl::trace(false, "fixme: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#endif
+
+// A macro to output a function call and its arguments to the debugging log, in case of error.
+#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF)
+#define ERR(message, ...) (void(0))
+#else
+#define ERR(message, ...) gl::trace(false, "err: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#endif
+
+// A macro to log a performance event around a scope.
+#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF)
+#define EVENT(message, ...) (void(0))
+#elif defined(_MSC_VER)
+#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper ## __LINE__(__FUNCTION__ message "\n", __VA_ARGS__);
+#else
+#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper(message "\n", ##__VA_ARGS__);
+#endif
+
+// A macro asserting a condition and outputting failures to the debug log
+#if !defined(NDEBUG)
+#define ASSERT(expression) do { \
+ if(!(expression)) \
+ ERR("\t! Assert failed in %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \
+ assert(expression); \
+ } while(0)
+#else
+#define ASSERT(expression) (void(0))
+#endif
+
+// A macro to indicate unimplemented functionality
+#if !defined(NDEBUG)
+#define UNIMPLEMENTED() do { \
+ FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+ } while(0)
+#else
+ #define UNIMPLEMENTED() FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__)
+#endif
+
+// A macro for code which is not expected to be reached under valid assumptions
+#if !defined(NDEBUG)
+#define UNREACHABLE() do { \
+ ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+ } while(0)
+#else
+ #define UNREACHABLE() ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__)
+#endif
+
+// A macro that determines whether an object has a given runtime type.
+#if !defined(NDEBUG) && (!defined(_MSC_VER) || defined(_CPPRTTI))
+#define HAS_DYNAMIC_TYPE(type, obj) (dynamic_cast<type >(obj) != NULL)
+#else
+#define HAS_DYNAMIC_TYPE(type, obj) true
+#endif
+
+// A macro functioning as a compile-time assert to validate constant conditions
+#define META_ASSERT(condition) typedef int COMPILE_TIME_ASSERT_##__LINE__[static_cast<bool>(condition)?1:-1]
+
+#endif // COMMON_DEBUG_H_
diff --git a/src/common/system.h b/src/common/system.h
new file mode 100644
index 00000000..5eb140bc
--- /dev/null
+++ b/src/common/system.h
@@ -0,0 +1,26 @@
+//
+// 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.
+//
+
+// system.h: Includes Windows system headers and undefines macros that conflict.
+
+#ifndef COMMON_SYSTEM_H
+#define COMMON_SYSTEM_H
+
+#if !defined(WIN32_LEAN_AND_MEAN)
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+
+#if defined(min)
+#undef min
+#endif
+
+#if defined(max)
+#undef max
+#endif
+
+#endif // COMMON_SYSTEM_H
diff --git a/src/common/version.h b/src/common/version.h
new file mode 100644
index 00000000..0353fb48
--- /dev/null
+++ b/src/common/version.h
@@ -0,0 +1,12 @@
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 2
+#define BUILD_VERSION 0
+#define BUILD_REVISION 2431
+
+#define STRINGIFY(x) #x
+#define MACRO_STRINGIFY(x) STRINGIFY(x)
+
+#define REVISION_STRING MACRO_STRINGIFY(BUILD_REVISION)
+#define VERSION_STRING MACRO_STRINGIFY(MAJOR_VERSION) "." MACRO_STRINGIFY(MINOR_VERSION) "." MACRO_STRINGIFY(BUILD_VERSION) "." MACRO_STRINGIFY(BUILD_REVISION)
+
+#define VERSION_DWORD ((MAJOR_VERSION << 24) | (MINOR_VERSION << 16) | BUILD_REVISION)
diff --git a/src/compiler/64bit-lexer-safety.patch b/src/compiler/64bit-lexer-safety.patch
new file mode 100644
index 00000000..7af91f57
--- /dev/null
+++ b/src/compiler/64bit-lexer-safety.patch
@@ -0,0 +1,177 @@
+--- a/src/compiler/glslang_lex.cpp
++++ b/src/compiler/glslang_lex.cpp
+@@ -68,6 +68,7 @@ typedef int16_t flex_int16_t;
+ typedef uint16_t flex_uint16_t;
+ typedef int32_t flex_int32_t;
+ typedef uint32_t flex_uint32_t;
++typedef uint64_t flex_uint64_t;
+ #else
+ typedef signed char flex_int8_t;
+ typedef short int flex_int16_t;
+@@ -191,6 +192,11 @@ typedef void* yyscan_t;
+ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ #endif
+
++#ifndef YY_TYPEDEF_YY_SIZE_T
++#define YY_TYPEDEF_YY_SIZE_T
++typedef size_t yy_size_t;
++#endif
++
+ #define EOB_ACT_CONTINUE_SCAN 0
+ #define EOB_ACT_END_OF_FILE 1
+ #define EOB_ACT_LAST_MATCH 2
+@@ -204,7 +210,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+- int yyl;\
++ yy_size_t yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+@@ -226,11 +232,6 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+ #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+-#ifndef YY_TYPEDEF_YY_SIZE_T
+-#define YY_TYPEDEF_YY_SIZE_T
+-typedef size_t yy_size_t;
+-#endif
+-
+ #ifndef YY_STRUCT_YY_BUFFER_STATE
+ #define YY_STRUCT_YY_BUFFER_STATE
+ struct yy_buffer_state
+@@ -248,7 +249,7 @@ struct yy_buffer_state
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+- int yy_n_chars;
++ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+@@ -327,7 +328,7 @@ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+ YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+ YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+ void *yyalloc (yy_size_t ,yyscan_t yyscanner );
+ void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+@@ -378,7 +379,7 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+ */
+ #define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+- yyleng = (size_t) (yy_cp - yy_bp); \
++ yyleng = (yy_size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+@@ -1035,8 +1036,8 @@ struct yyguts_t
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+- int yy_n_chars;
+- int yyleng_r;
++ yy_size_t yy_n_chars;
++ yy_size_t yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+@@ -1089,7 +1090,7 @@ FILE *yyget_out (yyscan_t yyscanner );
+
+ void yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+-int yyget_leng (yyscan_t yyscanner );
++yy_size_t yyget_leng (yyscan_t yyscanner );
+
+ char *yyget_text (yyscan_t yyscanner );
+
+@@ -1158,7 +1159,7 @@ static int input (yyscan_t yyscanner );
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+- int n; \
++ yy_size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+@@ -1317,7 +1318,7 @@ yy_find_action:
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+- int yyl;
++ yy_size_t yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+@@ -2203,7 +2204,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ else
+ {
+- int num_to_read =
++ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+@@ -2217,7 +2218,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ if ( b->yy_is_our_buffer )
+ {
+- int new_size = b->yy_buf_size * 2;
++ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+@@ -2248,7 +2249,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+- yyg->yy_n_chars, (size_t) num_to_read );
++ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+@@ -2373,7 +2374,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ else
+ { /* need more input */
+- int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
++ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+@@ -2660,7 +2661,7 @@ void yypop_buffer_state (yyscan_t yyscanner)
+ */
+ static void yyensure_buffer_stack (yyscan_t yyscanner)
+ {
+- int num_to_alloc;
++ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+@@ -2758,12 +2759,11 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+-YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+- yy_size_t n;
+- int i;
++ yy_size_t n, i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+@@ -2913,7 +2913,7 @@ FILE *yyget_out (yyscan_t yyscanner)
+ /** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+-int yyget_leng (yyscan_t yyscanner)
++yy_size_t yyget_leng (yyscan_t yyscanner)
+ {
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
diff --git a/src/compiler/BaseTypes.h b/src/compiler/BaseTypes.h
new file mode 100644
index 00000000..1631f4f7
--- /dev/null
+++ b/src/compiler/BaseTypes.h
@@ -0,0 +1,148 @@
+//
+// 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.
+//
+
+#ifndef _BASICTYPES_INCLUDED_
+#define _BASICTYPES_INCLUDED_
+
+//
+// Precision qualifiers
+//
+enum TPrecision
+{
+ // These need to be kept sorted
+ EbpUndefined,
+ EbpLow,
+ EbpMedium,
+ EbpHigh
+};
+
+inline const char* getPrecisionString(TPrecision p)
+{
+ switch(p)
+ {
+ case EbpHigh: return "highp"; break;
+ case EbpMedium: return "mediump"; break;
+ case EbpLow: return "lowp"; break;
+ default: return "mediump"; break; // Safest fallback
+ }
+}
+
+//
+// Basic type. Arrays, vectors, etc., are orthogonal to this.
+//
+enum TBasicType
+{
+ EbtVoid,
+ EbtFloat,
+ EbtInt,
+ EbtBool,
+ EbtGuardSamplerBegin, // non type: see implementation of IsSampler()
+ EbtSampler2D,
+ EbtSamplerCube,
+ EbtSamplerExternalOES, // Only valid if OES_EGL_image_external exists.
+ EbtSampler2DRect, // Only valid if GL_ARB_texture_rectangle exists.
+ EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
+ EbtStruct,
+ EbtAddress, // should be deprecated??
+ EbtInvariant // used as a type when qualifying a previously declared variable as being invariant
+};
+
+inline const char* getBasicString(TBasicType t)
+{
+ switch (t)
+ {
+ case EbtVoid: return "void"; break;
+ case EbtFloat: return "float"; break;
+ case EbtInt: return "int"; break;
+ case EbtBool: return "bool"; break;
+ case EbtSampler2D: return "sampler2D"; break;
+ case EbtSamplerCube: return "samplerCube"; break;
+ case EbtSamplerExternalOES: return "samplerExternalOES"; break;
+ case EbtSampler2DRect: return "sampler2DRect"; break;
+ case EbtStruct: return "structure"; break;
+ default: return "unknown type";
+ }
+}
+
+inline bool IsSampler(TBasicType type)
+{
+ return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd;
+}
+
+//
+// Qualifiers and built-ins. These are mainly used to see what can be read
+// or written, and by the machine dependent translator to know which registers
+// to allocate variables in. Since built-ins tend to go to different registers
+// than varying or uniform, it makes sense they are peers, not sub-classes.
+//
+enum TQualifier
+{
+ EvqTemporary, // For temporaries (within a function), read/write
+ EvqGlobal, // For globals read/write
+ EvqConst, // User defined constants and non-output parameters in functions
+ EvqAttribute, // Readonly
+ EvqVaryingIn, // readonly, fragment shaders only
+ EvqVaryingOut, // vertex shaders only read/write
+ EvqInvariantVaryingIn, // readonly, fragment shaders only
+ EvqInvariantVaryingOut, // vertex shaders only read/write
+ EvqUniform, // Readonly, vertex and fragment
+
+ // parameters
+ EvqIn,
+ EvqOut,
+ EvqInOut,
+ EvqConstReadOnly,
+
+ // built-ins written by vertex shader
+ EvqPosition,
+ EvqPointSize,
+
+ // built-ins read by fragment shader
+ EvqFragCoord,
+ EvqFrontFacing,
+ EvqPointCoord,
+
+ // built-ins written by fragment shader
+ EvqFragColor,
+ EvqFragData,
+ EvqFragDepth,
+
+ // end of list
+ EvqLast
+};
+
+//
+// This is just for debug print out, carried along with the definitions above.
+//
+inline const char* getQualifierString(TQualifier q)
+{
+ switch(q)
+ {
+ case EvqTemporary: return "Temporary"; break;
+ case EvqGlobal: return "Global"; break;
+ case EvqConst: return "const"; break;
+ case EvqConstReadOnly: return "const"; break;
+ case EvqAttribute: return "attribute"; break;
+ case EvqVaryingIn: return "varying"; break;
+ case EvqVaryingOut: return "varying"; break;
+ case EvqInvariantVaryingIn: return "invariant varying"; break;
+ case EvqInvariantVaryingOut:return "invariant varying"; break;
+ case EvqUniform: return "uniform"; break;
+ case EvqIn: return "in"; break;
+ case EvqOut: return "out"; break;
+ case EvqInOut: return "inout"; break;
+ case EvqPosition: return "Position"; break;
+ case EvqPointSize: return "PointSize"; break;
+ case EvqFragCoord: return "FragCoord"; break;
+ case EvqFrontFacing: return "FrontFacing"; break;
+ case EvqFragColor: return "FragColor"; break;
+ case EvqFragData: return "FragData"; break;
+ case EvqFragDepth: return "FragDepth"; break;
+ default: return "unknown qualifier";
+ }
+}
+
+#endif // _BASICTYPES_INCLUDED_
diff --git a/src/compiler/BuiltInFunctionEmulator.cpp b/src/compiler/BuiltInFunctionEmulator.cpp
new file mode 100644
index 00000000..1c4b25f1
--- /dev/null
+++ b/src/compiler/BuiltInFunctionEmulator.cpp
@@ -0,0 +1,406 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/BuiltInFunctionEmulator.h"
+
+#include "compiler/SymbolTable.h"
+
+namespace {
+
+// we use macros here instead of function definitions to work around more GLSL
+// compiler bugs, in particular on NVIDIA hardware on Mac OSX. Macros are
+// problematic because if the argument has side-effects they will be repeatedly
+// evaluated. This is unlikely to show up in real shaders, but is something to
+// consider.
+const char* kFunctionEmulationVertexSource[] = {
+ "#error no emulation for cos(float)",
+ "#error no emulation for cos(vec2)",
+ "#error no emulation for cos(vec3)",
+ "#error no emulation for cos(vec4)",
+
+ "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
+ "#error no emulation for distance(vec2, vec2)",
+ "#error no emulation for distance(vec3, vec3)",
+ "#error no emulation for distance(vec4, vec4)",
+
+ "#define webgl_dot_emu(x, y) ((x) * (y))",
+ "#error no emulation for dot(vec2, vec2)",
+ "#error no emulation for dot(vec3, vec3)",
+ "#error no emulation for dot(vec4, vec4)",
+
+ "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
+ "#error no emulation for length(vec2)",
+ "#error no emulation for length(vec3)",
+ "#error no emulation for length(vec4)",
+
+ "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
+ "#error no emulation for normalize(vec2)",
+ "#error no emulation for normalize(vec3)",
+ "#error no emulation for normalize(vec4)",
+
+ "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
+ "#error no emulation for reflect(vec2, vec2)",
+ "#error no emulation for reflect(vec3, vec3)",
+ "#error no emulation for reflect(vec4, vec4)"
+};
+
+const char* kFunctionEmulationFragmentSource[] = {
+ "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }",
+ "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }",
+ "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }",
+ "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }",
+
+ "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))",
+ "#error no emulation for distance(vec2, vec2)",
+ "#error no emulation for distance(vec3, vec3)",
+ "#error no emulation for distance(vec4, vec4)",
+
+ "#define webgl_dot_emu(x, y) ((x) * (y))",
+ "#error no emulation for dot(vec2, vec2)",
+ "#error no emulation for dot(vec3, vec3)",
+ "#error no emulation for dot(vec4, vec4)",
+
+ "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))",
+ "#error no emulation for length(vec2)",
+ "#error no emulation for length(vec3)",
+ "#error no emulation for length(vec4)",
+
+ "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))",
+ "#error no emulation for normalize(vec2)",
+ "#error no emulation for normalize(vec3)",
+ "#error no emulation for normalize(vec4)",
+
+ "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))",
+ "#error no emulation for reflect(vec2, vec2)",
+ "#error no emulation for reflect(vec3, vec3)",
+ "#error no emulation for reflect(vec4, vec4)"
+};
+
+const bool kFunctionEmulationVertexMask[] = {
+#if defined(__APPLE__)
+ // Work around ATI driver bugs in Mac.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ true, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ true, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ true, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ true, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ true, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#else
+ // Work around D3D driver bug in Win.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ false, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ false, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ false, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ false, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ false, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#endif
+ false // TFunctionUnknown
+};
+
+const bool kFunctionEmulationFragmentMask[] = {
+#if defined(__APPLE__)
+ // Work around ATI driver bugs in Mac.
+ true, // TFunctionCos1
+ true, // TFunctionCos2
+ true, // TFunctionCos3
+ true, // TFunctionCos4
+ true, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ true, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ true, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ true, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ true, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#else
+ // Work around D3D driver bug in Win.
+ false, // TFunctionCos1
+ false, // TFunctionCos2
+ false, // TFunctionCos3
+ false, // TFunctionCos4
+ false, // TFunctionDistance1_1
+ false, // TFunctionDistance2_2
+ false, // TFunctionDistance3_3
+ false, // TFunctionDistance4_4
+ false, // TFunctionDot1_1
+ false, // TFunctionDot2_2
+ false, // TFunctionDot3_3
+ false, // TFunctionDot4_4
+ false, // TFunctionLength1
+ false, // TFunctionLength2
+ false, // TFunctionLength3
+ false, // TFunctionLength4
+ false, // TFunctionNormalize1
+ false, // TFunctionNormalize2
+ false, // TFunctionNormalize3
+ false, // TFunctionNormalize4
+ false, // TFunctionReflect1_1
+ false, // TFunctionReflect2_2
+ false, // TFunctionReflect3_3
+ false, // TFunctionReflect4_4
+#endif
+ false // TFunctionUnknown
+};
+
+class BuiltInFunctionEmulationMarker : public TIntermTraverser {
+public:
+ BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator)
+ : mEmulator(emulator)
+ {
+ }
+
+ virtual bool visitUnary(Visit visit, TIntermUnary* node)
+ {
+ if (visit == PreVisit) {
+ bool needToEmulate = mEmulator.SetFunctionCalled(
+ node->getOp(), node->getOperand()->getType());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
+ {
+ if (visit == PreVisit) {
+ // Here we handle all the built-in functions instead of the ones we
+ // currently identified as problematic.
+ switch (node->getOp()) {
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ case EOpVectorEqual:
+ case EOpVectorNotEqual:
+ case EOpMod:
+ case EOpPow:
+ case EOpAtan:
+ case EOpMin:
+ case EOpMax:
+ case EOpClamp:
+ case EOpMix:
+ case EOpStep:
+ case EOpSmoothStep:
+ case EOpDistance:
+ case EOpDot:
+ case EOpCross:
+ case EOpFaceForward:
+ case EOpReflect:
+ case EOpRefract:
+ case EOpMul:
+ break;
+ default:
+ return true;
+ };
+ const TIntermSequence& sequence = node->getSequence();
+ // Right now we only handle built-in functions with two parameters.
+ if (sequence.size() != 2)
+ return true;
+ TIntermTyped* param1 = sequence[0]->getAsTyped();
+ TIntermTyped* param2 = sequence[1]->getAsTyped();
+ if (!param1 || !param2)
+ return true;
+ bool needToEmulate = mEmulator.SetFunctionCalled(
+ node->getOp(), param1->getType(), param2->getType());
+ if (needToEmulate)
+ node->setUseEmulatedFunction();
+ }
+ return true;
+ }
+
+private:
+ BuiltInFunctionEmulator& mEmulator;
+};
+
+} // anonymous namepsace
+
+BuiltInFunctionEmulator::BuiltInFunctionEmulator(ShShaderType shaderType)
+{
+ if (shaderType == SH_FRAGMENT_SHADER) {
+ mFunctionMask = kFunctionEmulationFragmentMask;
+ mFunctionSource = kFunctionEmulationFragmentSource;
+ } else {
+ mFunctionMask = kFunctionEmulationVertexMask;
+ mFunctionSource = kFunctionEmulationVertexSource;
+ }
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(
+ TOperator op, const TType& param)
+{
+ TBuiltInFunction function = IdentifyFunction(op, param);
+ return SetFunctionCalled(function);
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(
+ TOperator op, const TType& param1, const TType& param2)
+{
+ TBuiltInFunction function = IdentifyFunction(op, param1, param2);
+ return SetFunctionCalled(function);
+}
+
+bool BuiltInFunctionEmulator::SetFunctionCalled(
+ BuiltInFunctionEmulator::TBuiltInFunction function) {
+ if (function == TFunctionUnknown || mFunctionMask[function] == false)
+ return false;
+ for (size_t i = 0; i < mFunctions.size(); ++i) {
+ if (mFunctions[i] == function)
+ return true;
+ }
+ mFunctions.push_back(function);
+ return true;
+}
+
+void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition(
+ TInfoSinkBase& out, bool withPrecision) const
+{
+ if (mFunctions.size() == 0)
+ return;
+ out << "// BEGIN: Generated code for built-in function emulation\n\n";
+ if (withPrecision) {
+ out << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
+ << "#define webgl_emu_precision highp\n"
+ << "#else\n"
+ << "#define webgl_emu_precision mediump\n"
+ << "#endif\n\n";
+ } else {
+ out << "#define webgl_emu_precision\n\n";
+ }
+ for (size_t i = 0; i < mFunctions.size(); ++i) {
+ out << mFunctionSource[mFunctions[i]] << "\n\n";
+ }
+ out << "// END: Generated code for built-in function emulation\n\n";
+}
+
+BuiltInFunctionEmulator::TBuiltInFunction
+BuiltInFunctionEmulator::IdentifyFunction(
+ TOperator op, const TType& param)
+{
+ if (param.getNominalSize() > 4)
+ return TFunctionUnknown;
+ unsigned int function = TFunctionUnknown;
+ switch (op) {
+ case EOpCos:
+ function = TFunctionCos1;
+ break;
+ case EOpLength:
+ function = TFunctionLength1;
+ break;
+ case EOpNormalize:
+ function = TFunctionNormalize1;
+ break;
+ default:
+ break;
+ }
+ if (function == TFunctionUnknown)
+ return TFunctionUnknown;
+ if (param.isVector())
+ function += param.getNominalSize() - 1;
+ return static_cast<TBuiltInFunction>(function);
+}
+
+BuiltInFunctionEmulator::TBuiltInFunction
+BuiltInFunctionEmulator::IdentifyFunction(
+ TOperator op, const TType& param1, const TType& param2)
+{
+ // Right now for all the emulated functions with two parameters, the two
+ // parameters have the same type.
+ if (param1.isVector() != param2.isVector() ||
+ param1.getNominalSize() != param2.getNominalSize() ||
+ param1.getNominalSize() > 4)
+ return TFunctionUnknown;
+
+ unsigned int function = TFunctionUnknown;
+ switch (op) {
+ case EOpDistance:
+ function = TFunctionDistance1_1;
+ break;
+ case EOpDot:
+ function = TFunctionDot1_1;
+ break;
+ case EOpReflect:
+ function = TFunctionReflect1_1;
+ break;
+ default:
+ break;
+ }
+ if (function == TFunctionUnknown)
+ return TFunctionUnknown;
+ if (param1.isVector())
+ function += param1.getNominalSize() - 1;
+ return static_cast<TBuiltInFunction>(function);
+}
+
+void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation(
+ TIntermNode* root)
+{
+ ASSERT(root);
+
+ BuiltInFunctionEmulationMarker marker(*this);
+ root->traverse(&marker);
+}
+
+void BuiltInFunctionEmulator::Cleanup()
+{
+ mFunctions.clear();
+}
+
+//static
+TString BuiltInFunctionEmulator::GetEmulatedFunctionName(
+ const TString& name)
+{
+ ASSERT(name[name.length() - 1] == '(');
+ return "webgl_" + name.substr(0, name.length() - 1) + "_emu(";
+}
+
diff --git a/src/compiler/BuiltInFunctionEmulator.h b/src/compiler/BuiltInFunctionEmulator.h
new file mode 100644
index 00000000..0d904f41
--- /dev/null
+++ b/src/compiler/BuiltInFunctionEmulator.h
@@ -0,0 +1,93 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
+#define COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/intermediate.h"
+
+//
+// This class decides which built-in functions need to be replaced with the
+// emulated ones.
+// It's only a workaround for OpenGL driver bugs, and isn't needed in general.
+//
+class BuiltInFunctionEmulator {
+public:
+ BuiltInFunctionEmulator(ShShaderType shaderType);
+ // Records that a function is called by the shader and might needs to be
+ // emulated. If the function's group is not in mFunctionGroupFilter, this
+ // becomes an no-op.
+ // Returns true if the function call needs to be replaced with an emulated
+ // one.
+ bool SetFunctionCalled(TOperator op, const TType& param);
+ bool SetFunctionCalled(
+ TOperator op, const TType& param1, const TType& param2);
+
+ // Output function emulation definition. This should be before any other
+ // shader source.
+ void OutputEmulatedFunctionDefinition(TInfoSinkBase& out, bool withPrecision) const;
+
+ void MarkBuiltInFunctionsForEmulation(TIntermNode* root);
+
+ void Cleanup();
+
+ // "name(" becomes "webgl_name_emu(".
+ static TString GetEmulatedFunctionName(const TString& name);
+
+private:
+ //
+ // Built-in functions.
+ //
+ enum TBuiltInFunction {
+ TFunctionCos1 = 0, // float cos(float);
+ TFunctionCos2, // vec2 cos(vec2);
+ TFunctionCos3, // vec3 cos(vec3);
+ TFunctionCos4, // vec4 cos(vec4);
+
+ TFunctionDistance1_1, // float distance(float, float);
+ TFunctionDistance2_2, // vec2 distance(vec2, vec2);
+ TFunctionDistance3_3, // vec3 distance(vec3, vec3);
+ TFunctionDistance4_4, // vec4 distance(vec4, vec4);
+
+ TFunctionDot1_1, // float dot(float, float);
+ TFunctionDot2_2, // vec2 dot(vec2, vec2);
+ TFunctionDot3_3, // vec3 dot(vec3, vec3);
+ TFunctionDot4_4, // vec4 dot(vec4, vec4);
+
+ TFunctionLength1, // float length(float);
+ TFunctionLength2, // float length(vec2);
+ TFunctionLength3, // float length(vec3);
+ TFunctionLength4, // float length(vec4);
+
+ TFunctionNormalize1, // float normalize(float);
+ TFunctionNormalize2, // vec2 normalize(vec2);
+ TFunctionNormalize3, // vec3 normalize(vec3);
+ TFunctionNormalize4, // vec4 normalize(vec4);
+
+ TFunctionReflect1_1, // float reflect(float, float);
+ TFunctionReflect2_2, // vec2 reflect(vec2, vec2);
+ TFunctionReflect3_3, // vec3 reflect(vec3, vec3);
+ TFunctionReflect4_4, // vec4 reflect(vec4, vec4);
+
+ TFunctionUnknown
+ };
+
+ TBuiltInFunction IdentifyFunction(TOperator op, const TType& param);
+ TBuiltInFunction IdentifyFunction(
+ TOperator op, const TType& param1, const TType& param2);
+
+ bool SetFunctionCalled(TBuiltInFunction function);
+
+ std::vector<TBuiltInFunction> mFunctions;
+
+ const bool* mFunctionMask; // a boolean flag for each function.
+ const char** mFunctionSource;
+};
+
+#endif // COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_
diff --git a/src/compiler/CodeGenGLSL.cpp b/src/compiler/CodeGenGLSL.cpp
new file mode 100644
index 00000000..226bf8f0
--- /dev/null
+++ b/src/compiler/CodeGenGLSL.cpp
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+#include "compiler/TranslatorGLSL.h"
+#include "compiler/TranslatorESSL.h"
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code. It returns
+// a subclass of TCompiler.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+{
+ switch (output) {
+ case SH_GLSL_OUTPUT:
+ return new TranslatorGLSL(type, spec);
+ case SH_ESSL_OUTPUT:
+ return new TranslatorESSL(type, spec);
+ default:
+ return NULL;
+ }
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+ delete compiler;
+}
diff --git a/src/compiler/CodeGenHLSL.cpp b/src/compiler/CodeGenHLSL.cpp
new file mode 100644
index 00000000..637ccc5e
--- /dev/null
+++ b/src/compiler/CodeGenHLSL.cpp
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+
+#include "compiler/TranslatorHLSL.h"
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code. It returns
+// a subclass of TCompiler.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+{
+ switch (output)
+ {
+ case SH_HLSL9_OUTPUT:
+ case SH_HLSL11_OUTPUT:
+ return new TranslatorHLSL(type, spec, output);
+ default:
+ return NULL;
+ }
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+ delete compiler;
+}
diff --git a/src/compiler/Common.h b/src/compiler/Common.h
new file mode 100644
index 00000000..46f9440f
--- /dev/null
+++ b/src/compiler/Common.h
@@ -0,0 +1,77 @@
+//
+// 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.
+//
+
+#ifndef _COMMON_INCLUDED_
+#define _COMMON_INCLUDED_
+
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "compiler/PoolAlloc.h"
+
+struct TSourceLoc {
+ int first_file;
+ int first_line;
+ int last_file;
+ int last_line;
+};
+
+//
+// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
+//
+#define POOL_ALLOCATOR_NEW_DELETE() \
+ void* operator new(size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \
+ void* operator new(size_t, void *_Where) { return (_Where); } \
+ void operator delete(void*) { } \
+ void operator delete(void *, void *) { } \
+ void* operator new[](size_t s) { return GetGlobalPoolAllocator()->allocate(s); } \
+ void* operator new[](size_t, void *_Where) { return (_Where); } \
+ void operator delete[](void*) { } \
+ void operator delete[](void *, void *) { }
+
+//
+// Pool version of string.
+//
+typedef pool_allocator<char> TStringAllocator;
+typedef std::basic_string <char, std::char_traits<char>, TStringAllocator> TString;
+typedef std::basic_ostringstream<char, std::char_traits<char>, TStringAllocator> TStringStream;
+inline TString* NewPoolTString(const char* s)
+{
+ void* memory = GetGlobalPoolAllocator()->allocate(sizeof(TString));
+ return new(memory) TString(s);
+}
+
+//
+// Persistent string memory. Should only be used for strings that survive
+// across compiles.
+//
+#define TPersistString std::string
+#define TPersistStringStream std::ostringstream
+
+//
+// Pool allocator versions of vectors, lists, and maps
+//
+template <class T> class TVector : public std::vector<T, pool_allocator<T> > {
+public:
+ typedef typename std::vector<T, pool_allocator<T> >::size_type size_type;
+ TVector() : std::vector<T, pool_allocator<T> >() {}
+ TVector(const pool_allocator<T>& a) : std::vector<T, pool_allocator<T> >(a) {}
+ TVector(size_type i): std::vector<T, pool_allocator<T> >(i) {}
+};
+
+template <class K, class D, class CMP = std::less<K> >
+class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D> > > {
+public:
+ typedef pool_allocator<std::pair<const K, D> > tAllocator;
+
+ TMap() : std::map<K, D, CMP, tAllocator>() {}
+ // use correct two-stage name lookup supported in gcc 3.4 and above
+ TMap(const tAllocator& a) : std::map<K, D, CMP, tAllocator>(std::map<K, D, CMP, tAllocator>::key_compare(), a) {}
+};
+
+#endif // _COMMON_INCLUDED_
diff --git a/src/compiler/Compiler.cpp b/src/compiler/Compiler.cpp
new file mode 100644
index 00000000..3e80d96a
--- /dev/null
+++ b/src/compiler/Compiler.cpp
@@ -0,0 +1,408 @@
+//
+// 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.
+//
+
+#include "compiler/BuiltInFunctionEmulator.h"
+#include "compiler/DetectCallDepth.h"
+#include "compiler/ForLoopUnroll.h"
+#include "compiler/Initialize.h"
+#include "compiler/InitializeParseContext.h"
+#include "compiler/MapLongVariableNames.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/RenameFunction.h"
+#include "compiler/ShHandle.h"
+#include "compiler/ValidateLimitations.h"
+#include "compiler/VariablePacker.h"
+#include "compiler/depgraph/DependencyGraph.h"
+#include "compiler/depgraph/DependencyGraphOutput.h"
+#include "compiler/timing/RestrictFragmentShaderTiming.h"
+#include "compiler/timing/RestrictVertexShaderTiming.h"
+#include "third_party/compiler/ArrayBoundsClamper.h"
+
+bool isWebGLBasedSpec(ShShaderSpec spec)
+{
+ return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC;
+}
+
+namespace {
+class TScopedPoolAllocator {
+public:
+ TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
+ : mAllocator(allocator), mPushPopAllocator(pushPop) {
+ if (mPushPopAllocator) mAllocator->push();
+ SetGlobalPoolAllocator(mAllocator);
+ }
+ ~TScopedPoolAllocator() {
+ SetGlobalPoolAllocator(NULL);
+ if (mPushPopAllocator) mAllocator->pop();
+ }
+
+private:
+ TPoolAllocator* mAllocator;
+ bool mPushPopAllocator;
+};
+} // namespace
+
+TShHandleBase::TShHandleBase() {
+ allocator.push();
+ SetGlobalPoolAllocator(&allocator);
+}
+
+TShHandleBase::~TShHandleBase() {
+ SetGlobalPoolAllocator(NULL);
+ allocator.popAll();
+}
+
+TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
+ : shaderType(type),
+ shaderSpec(spec),
+ maxUniformVectors(0),
+ maxExpressionComplexity(0),
+ maxCallStackDepth(0),
+ fragmentPrecisionHigh(false),
+ clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
+ builtInFunctionEmulator(type)
+{
+ longNameMap = LongNameMap::GetInstance();
+}
+
+TCompiler::~TCompiler()
+{
+ ASSERT(longNameMap);
+ longNameMap->Release();
+}
+
+bool TCompiler::Init(const ShBuiltInResources& resources)
+{
+ maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
+ resources.MaxVertexUniformVectors :
+ resources.MaxFragmentUniformVectors;
+ maxExpressionComplexity = resources.MaxExpressionComplexity;
+ maxCallStackDepth = resources.MaxCallStackDepth;
+ TScopedPoolAllocator scopedAlloc(&allocator, false);
+
+ // Generate built-in symbol table.
+ if (!InitBuiltInSymbolTable(resources))
+ return false;
+ InitExtensionBehavior(resources, extensionBehavior);
+ fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
+
+ arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
+ clampingStrategy = resources.ArrayIndexClampingStrategy;
+
+ hashFunction = resources.HashFunction;
+
+ return true;
+}
+
+bool TCompiler::compile(const char* const shaderStrings[],
+ size_t numStrings,
+ int compileOptions)
+{
+ TScopedPoolAllocator scopedAlloc(&allocator, true);
+ clearResults();
+
+ if (numStrings == 0)
+ return true;
+
+ // If compiling for WebGL, validate loop and indexing as well.
+ if (isWebGLBasedSpec(shaderSpec))
+ compileOptions |= SH_VALIDATE_LOOP_INDEXING;
+
+ // First string is path of source file if flag is set. The actual source follows.
+ const char* sourcePath = NULL;
+ size_t firstSource = 0;
+ if (compileOptions & SH_SOURCE_PATH)
+ {
+ sourcePath = shaderStrings[0];
+ ++firstSource;
+ }
+
+ TIntermediate intermediate(infoSink);
+ TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
+ shaderType, shaderSpec, compileOptions, true,
+ sourcePath, infoSink);
+ parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh;
+ SetGlobalParseContext(&parseContext);
+
+ // We preserve symbols at the built-in level from compile-to-compile.
+ // Start pushing the user-defined symbols at global level.
+ symbolTable.push();
+ if (!symbolTable.atGlobalLevel()) {
+ infoSink.info.prefix(EPrefixInternalError);
+ infoSink.info << "Wrong symbol table level";
+ }
+
+ // Parse shader.
+ bool success =
+ (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
+ (parseContext.treeRoot != NULL);
+ if (success) {
+ TIntermNode* root = parseContext.treeRoot;
+ success = intermediate.postProcess(root);
+
+ if (success)
+ success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
+
+ if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
+ success = validateLimitations(root);
+
+ if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
+ success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
+
+ if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
+ rewriteCSSShader(root);
+
+ // Unroll for-loop markup needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
+ ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
+
+ // Built-in function emulation needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
+ builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
+
+ // Clamping uniform array bounds needs to happen after validateLimitations pass.
+ if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
+ arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
+
+ // Disallow expressions deemed too complex.
+ if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
+ success = limitExpressionComplexity(root);
+
+ // Call mapLongVariableNames() before collectAttribsUniforms() so in
+ // collectAttribsUniforms() we already have the mapped symbol names and
+ // we could composite mapped and original variable names.
+ // Also, if we hash all the names, then no need to do this for long names.
+ if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL)
+ mapLongVariableNames(root);
+
+ if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) {
+ collectAttribsUniforms(root);
+ if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) {
+ success = enforcePackingRestrictions();
+ if (!success) {
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "too many uniforms";
+ }
+ }
+ }
+
+ if (success && (compileOptions & SH_INTERMEDIATE_TREE))
+ intermediate.outputTree(root);
+
+ if (success && (compileOptions & SH_OBJECT_CODE))
+ translate(root);
+ }
+
+ // Cleanup memory.
+ intermediate.remove(parseContext.treeRoot);
+ // Ensure symbol table is returned to the built-in level,
+ // throwing away all but the built-ins.
+ while (!symbolTable.atBuiltInLevel())
+ symbolTable.pop();
+
+ return success;
+}
+
+bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
+{
+ compileResources = resources;
+
+ assert(symbolTable.isEmpty());
+ symbolTable.push();
+
+ TPublicType integer;
+ integer.type = EbtInt;
+ integer.size = 1;
+ integer.matrix = false;
+ integer.array = false;
+
+ TPublicType floatingPoint;
+ floatingPoint.type = EbtFloat;
+ floatingPoint.size = 1;
+ floatingPoint.matrix = false;
+ floatingPoint.array = false;
+
+ switch(shaderType)
+ {
+ case SH_FRAGMENT_SHADER:
+ symbolTable.setDefaultPrecision(integer, EbpMedium);
+ break;
+ case SH_VERTEX_SHADER:
+ symbolTable.setDefaultPrecision(integer, EbpHigh);
+ symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
+ break;
+ default: assert(false && "Language not supported");
+ }
+
+ InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
+
+ IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
+
+ return true;
+}
+
+void TCompiler::clearResults()
+{
+ arrayBoundsClamper.Cleanup();
+ infoSink.info.erase();
+ infoSink.obj.erase();
+ infoSink.debug.erase();
+
+ attribs.clear();
+ uniforms.clear();
+
+ builtInFunctionEmulator.Cleanup();
+
+ nameMap.clear();
+}
+
+bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
+{
+ DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
+ root->traverse(&detect);
+ switch (detect.detectCallDepth()) {
+ case DetectCallDepth::kErrorNone:
+ return true;
+ case DetectCallDepth::kErrorMissingMain:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Missing main()";
+ return false;
+ case DetectCallDepth::kErrorRecursion:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Function recursion detected";
+ return false;
+ case DetectCallDepth::kErrorMaxDepthExceeded:
+ infoSink.info.prefix(EPrefixError);
+ infoSink.info << "Function call stack too deep";
+ return false;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+void TCompiler::rewriteCSSShader(TIntermNode* root)
+{
+ RenameFunction renamer("main(", "css_main(");
+ root->traverse(&renamer);
+}
+
+bool TCompiler::validateLimitations(TIntermNode* root) {
+ ValidateLimitations validate(shaderType, infoSink.info);
+ root->traverse(&validate);
+ return validate.numErrors() == 0;
+}
+
+bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
+{
+ if (shaderSpec != SH_WEBGL_SPEC) {
+ infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
+ return false;
+ }
+
+ if (shaderType == SH_FRAGMENT_SHADER) {
+ TDependencyGraph graph(root);
+
+ // Output any errors first.
+ bool success = enforceFragmentShaderTimingRestrictions(graph);
+
+ // Then, output the dependency graph.
+ if (outputGraph) {
+ TDependencyGraphOutput output(infoSink.info);
+ output.outputAllSpanningTrees(graph);
+ }
+
+ return success;
+ }
+ else {
+ return enforceVertexShaderTimingRestrictions(root);
+ }
+}
+
+bool TCompiler::limitExpressionComplexity(TIntermNode* root)
+{
+ TIntermTraverser traverser;
+ root->traverse(&traverser);
+ TDependencyGraph graph(root);
+
+ for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
+ iter != graph.endUserDefinedFunctionCalls();
+ ++iter)
+ {
+ TGraphFunctionCall* samplerSymbol = *iter;
+ TDependencyGraphTraverser graphTraverser;
+ samplerSymbol->traverse(&graphTraverser);
+ }
+
+ if (traverser.getMaxDepth() > maxExpressionComplexity) {
+ infoSink.info << "Expression too complex.";
+ return false;
+ }
+ return true;
+}
+
+bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
+{
+ RestrictFragmentShaderTiming restrictor(infoSink.info);
+ restrictor.enforceRestrictions(graph);
+ return restrictor.numErrors() == 0;
+}
+
+bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
+{
+ RestrictVertexShaderTiming restrictor(infoSink.info);
+ restrictor.enforceRestrictions(root);
+ return restrictor.numErrors() == 0;
+}
+
+void TCompiler::collectAttribsUniforms(TIntermNode* root)
+{
+ CollectAttribsUniforms collect(attribs, uniforms, hashFunction);
+ root->traverse(&collect);
+}
+
+bool TCompiler::enforcePackingRestrictions()
+{
+ VariablePacker packer;
+ return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms);
+}
+
+void TCompiler::mapLongVariableNames(TIntermNode* root)
+{
+ ASSERT(longNameMap);
+ MapLongVariableNames map(longNameMap);
+ root->traverse(&map);
+}
+
+int TCompiler::getMappedNameMaxLength() const
+{
+ return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
+}
+
+const TExtensionBehavior& TCompiler::getExtensionBehavior() const
+{
+ return extensionBehavior;
+}
+
+const ShBuiltInResources& TCompiler::getResources() const
+{
+ return compileResources;
+}
+
+const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
+{
+ return arrayBoundsClamper;
+}
+
+ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
+{
+ return clampingStrategy;
+}
+
+const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
+{
+ return builtInFunctionEmulator;
+}
diff --git a/src/compiler/ConstantUnion.h b/src/compiler/ConstantUnion.h
new file mode 100644
index 00000000..b1e37885
--- /dev/null
+++ b/src/compiler/ConstantUnion.h
@@ -0,0 +1,257 @@
+//
+// 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.
+//
+
+#ifndef _CONSTANT_UNION_INCLUDED_
+#define _CONSTANT_UNION_INCLUDED_
+
+#include <assert.h>
+
+class ConstantUnion {
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ ConstantUnion()
+ {
+ iConst = 0;
+ type = EbtVoid;
+ }
+
+ void setIConst(int i) {iConst = i; type = EbtInt; }
+ void setFConst(float f) {fConst = f; type = EbtFloat; }
+ void setBConst(bool b) {bConst = b; type = EbtBool; }
+
+ int getIConst() { return iConst; }
+ float getFConst() { return fConst; }
+ bool getBConst() { return bConst; }
+ int getIConst() const { return iConst; }
+ float getFConst() const { return fConst; }
+ bool getBConst() const { return bConst; }
+
+ bool operator==(const int i) const
+ {
+ return i == iConst;
+ }
+
+ bool operator==(const float f) const
+ {
+ return f == fConst;
+ }
+
+ bool operator==(const bool b) const
+ {
+ return b == bConst;
+ }
+
+ bool operator==(const ConstantUnion& constant) const
+ {
+ if (constant.type != type)
+ return false;
+
+ switch (type) {
+ case EbtInt:
+ return constant.iConst == iConst;
+ case EbtFloat:
+ return constant.fConst == fConst;
+ case EbtBool:
+ return constant.bConst == bConst;
+ default:
+ return false;
+ }
+ }
+
+ bool operator!=(const int i) const
+ {
+ return !operator==(i);
+ }
+
+ bool operator!=(const float f) const
+ {
+ return !operator==(f);
+ }
+
+ bool operator!=(const bool b) const
+ {
+ return !operator==(b);
+ }
+
+ bool operator!=(const ConstantUnion& constant) const
+ {
+ return !operator==(constant);
+ }
+
+ bool operator>(const ConstantUnion& constant) const
+ {
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt:
+ return iConst > constant.iConst;
+ case EbtFloat:
+ return fConst > constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+ }
+
+ bool operator<(const ConstantUnion& constant) const
+ {
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt:
+ return iConst < constant.iConst;
+ case EbtFloat:
+ return fConst < constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+ }
+
+ ConstantUnion operator+(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
+ case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator-(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
+ case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator*(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
+ case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator%(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator>>(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator<<(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst << constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator&(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst & constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator|(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst | constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator^(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator&&(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator||(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ TBasicType getType() const { return type; }
+private:
+
+ union {
+ int iConst; // used for ivec, scalar ints
+ bool bConst; // used for bvec, scalar bools
+ float fConst; // used for vec, mat, scalar floats
+ } ;
+
+ TBasicType type;
+};
+
+#endif // _CONSTANT_UNION_INCLUDED_
diff --git a/src/compiler/DetectCallDepth.cpp b/src/compiler/DetectCallDepth.cpp
new file mode 100644
index 00000000..60df52c7
--- /dev/null
+++ b/src/compiler/DetectCallDepth.cpp
@@ -0,0 +1,185 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/DetectCallDepth.h"
+#include "compiler/InfoSink.h"
+
+DetectCallDepth::FunctionNode::FunctionNode(const TString& fname)
+ : name(fname),
+ visit(PreVisit)
+{
+}
+
+const TString& DetectCallDepth::FunctionNode::getName() const
+{
+ return name;
+}
+
+void DetectCallDepth::FunctionNode::addCallee(
+ DetectCallDepth::FunctionNode* callee)
+{
+ for (size_t i = 0; i < callees.size(); ++i) {
+ if (callees[i] == callee)
+ return;
+ }
+ callees.push_back(callee);
+}
+
+int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDepth, int depth)
+{
+ ASSERT(visit == PreVisit);
+ ASSERT(detectCallDepth);
+
+ int maxDepth = depth;
+ visit = InVisit;
+ for (size_t i = 0; i < callees.size(); ++i) {
+ switch (callees[i]->visit) {
+ case InVisit:
+ // cycle detected, i.e., recursion detected.
+ return kInfiniteCallDepth;
+ case PostVisit:
+ break;
+ case PreVisit: {
+ // Check before we recurse so we don't go too depth
+ if (detectCallDepth->checkExceedsMaxDepth(depth))
+ return depth;
+ int callDepth = callees[i]->detectCallDepth(detectCallDepth, depth + 1);
+ // Check after we recurse so we can exit immediately and provide info.
+ if (detectCallDepth->checkExceedsMaxDepth(callDepth)) {
+ detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName();
+ return callDepth;
+ }
+ maxDepth = std::max(callDepth, maxDepth);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ visit = PostVisit;
+ return maxDepth;
+}
+
+void DetectCallDepth::FunctionNode::reset()
+{
+ visit = PreVisit;
+}
+
+DetectCallDepth::DetectCallDepth(TInfoSink& infoSink, bool limitCallStackDepth, int maxCallStackDepth)
+ : TIntermTraverser(true, false, true, false),
+ currentFunction(NULL),
+ infoSink(infoSink),
+ maxDepth(limitCallStackDepth ? maxCallStackDepth : FunctionNode::kInfiniteCallDepth)
+{
+}
+
+DetectCallDepth::~DetectCallDepth()
+{
+ for (size_t i = 0; i < functions.size(); ++i)
+ delete functions[i];
+}
+
+bool DetectCallDepth::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ switch (node->getOp())
+ {
+ case EOpPrototype:
+ // Function declaration.
+ // Don't add FunctionNode here because node->getName() is the
+ // unmangled function name.
+ break;
+ case EOpFunction: {
+ // Function definition.
+ if (visit == PreVisit) {
+ currentFunction = findFunctionByName(node->getName());
+ if (currentFunction == NULL) {
+ currentFunction = new FunctionNode(node->getName());
+ functions.push_back(currentFunction);
+ }
+ } else if (visit == PostVisit) {
+ currentFunction = NULL;
+ }
+ break;
+ }
+ case EOpFunctionCall: {
+ // Function call.
+ if (visit == PreVisit) {
+ FunctionNode* func = findFunctionByName(node->getName());
+ if (func == NULL) {
+ func = new FunctionNode(node->getName());
+ functions.push_back(func);
+ }
+ if (currentFunction)
+ currentFunction->addCallee(func);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return true;
+}
+
+bool DetectCallDepth::checkExceedsMaxDepth(int depth)
+{
+ return depth >= maxDepth;
+}
+
+void DetectCallDepth::resetFunctionNodes()
+{
+ for (size_t i = 0; i < functions.size(); ++i) {
+ functions[i]->reset();
+ }
+}
+
+DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepthForFunction(FunctionNode* func)
+{
+ currentFunction = NULL;
+ resetFunctionNodes();
+
+ int maxCallDepth = func->detectCallDepth(this, 1);
+
+ if (maxCallDepth == FunctionNode::kInfiniteCallDepth)
+ return kErrorRecursion;
+
+ if (maxCallDepth >= maxDepth)
+ return kErrorMaxDepthExceeded;
+
+ return kErrorNone;
+}
+
+DetectCallDepth::ErrorCode DetectCallDepth::detectCallDepth()
+{
+ if (maxDepth != FunctionNode::kInfiniteCallDepth) {
+ // Check all functions because the driver may fail on them
+ // TODO: Before detectingRecursion, strip unused functions.
+ for (size_t i = 0; i < functions.size(); ++i) {
+ ErrorCode error = detectCallDepthForFunction(functions[i]);
+ if (error != kErrorNone)
+ return error;
+ }
+ } else {
+ FunctionNode* main = findFunctionByName("main(");
+ if (main == NULL)
+ return kErrorMissingMain;
+
+ return detectCallDepthForFunction(main);
+ }
+
+ return kErrorNone;
+}
+
+DetectCallDepth::FunctionNode* DetectCallDepth::findFunctionByName(
+ const TString& name)
+{
+ for (size_t i = 0; i < functions.size(); ++i) {
+ if (functions[i]->getName() == name)
+ return functions[i];
+ }
+ return NULL;
+}
+
diff --git a/src/compiler/DetectCallDepth.h b/src/compiler/DetectCallDepth.h
new file mode 100644
index 00000000..89e85f88
--- /dev/null
+++ b/src/compiler/DetectCallDepth.h
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DETECT_RECURSION_H_
+#define COMPILER_DETECT_RECURSION_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include <limits.h>
+#include "compiler/intermediate.h"
+#include "compiler/VariableInfo.h"
+
+class TInfoSink;
+
+// Traverses intermediate tree to detect function recursion.
+class DetectCallDepth : public TIntermTraverser {
+public:
+ enum ErrorCode {
+ kErrorMissingMain,
+ kErrorRecursion,
+ kErrorMaxDepthExceeded,
+ kErrorNone
+ };
+
+ DetectCallDepth(TInfoSink& infoSync, bool limitCallStackDepth, int maxCallStackDepth);
+ ~DetectCallDepth();
+
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+
+ bool checkExceedsMaxDepth(int depth);
+
+ ErrorCode detectCallDepth();
+
+private:
+ class FunctionNode {
+ public:
+ static const int kInfiniteCallDepth = INT_MAX;
+
+ FunctionNode(const TString& fname);
+
+ const TString& getName() const;
+
+ // If a function is already in the callee list, this becomes a no-op.
+ void addCallee(FunctionNode* callee);
+
+ // Returns kInifinityCallDepth if recursive function calls are detected.
+ int detectCallDepth(DetectCallDepth* detectCallDepth, int depth);
+
+ // Reset state.
+ void reset();
+
+ private:
+ // mangled function name is unique.
+ TString name;
+
+ // functions that are directly called by this function.
+ TVector<FunctionNode*> callees;
+
+ Visit visit;
+ };
+
+ ErrorCode detectCallDepthForFunction(FunctionNode* func);
+ FunctionNode* findFunctionByName(const TString& name);
+ void resetFunctionNodes();
+
+ TInfoSink& getInfoSink() { return infoSink; }
+
+ TVector<FunctionNode*> functions;
+ FunctionNode* currentFunction;
+ TInfoSink& infoSink;
+ int maxDepth;
+
+ DetectCallDepth(const DetectCallDepth&);
+ void operator=(const DetectCallDepth&);
+};
+
+#endif // COMPILER_DETECT_RECURSION_H_
diff --git a/src/compiler/DetectDiscontinuity.cpp b/src/compiler/DetectDiscontinuity.cpp
new file mode 100644
index 00000000..7c3b68a0
--- /dev/null
+++ b/src/compiler/DetectDiscontinuity.cpp
@@ -0,0 +1,139 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Contains analysis utilities for dealing with HLSL's lack of support for
+// the use of intrinsic functions which (implicitly or explicitly) compute
+// gradients of functions with discontinuities.
+//
+
+#include "compiler/DetectDiscontinuity.h"
+
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+bool DetectLoopDiscontinuity::traverse(TIntermNode *node)
+{
+ mLoopDepth = 0;
+ mLoopDiscontinuity = false;
+ node->traverse(this);
+ return mLoopDiscontinuity;
+}
+
+bool DetectLoopDiscontinuity::visitLoop(Visit visit, TIntermLoop *loop)
+{
+ if (visit == PreVisit)
+ {
+ ++mLoopDepth;
+ }
+ else if (visit == PostVisit)
+ {
+ --mLoopDepth;
+ }
+
+ return true;
+}
+
+bool DetectLoopDiscontinuity::visitBranch(Visit visit, TIntermBranch *node)
+{
+ if (mLoopDiscontinuity)
+ {
+ return false;
+ }
+
+ if (!mLoopDepth)
+ {
+ return true;
+ }
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill:
+ break;
+ case EOpBreak:
+ case EOpContinue:
+ case EOpReturn:
+ mLoopDiscontinuity = true;
+ break;
+ default: UNREACHABLE();
+ }
+
+ return !mLoopDiscontinuity;
+}
+
+bool DetectLoopDiscontinuity::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ return !mLoopDiscontinuity;
+}
+
+bool containsLoopDiscontinuity(TIntermNode *node)
+{
+ DetectLoopDiscontinuity detectLoopDiscontinuity;
+ return detectLoopDiscontinuity.traverse(node);
+}
+
+bool DetectGradientOperation::traverse(TIntermNode *node)
+{
+ mGradientOperation = false;
+ node->traverse(this);
+ return mGradientOperation;
+}
+
+bool DetectGradientOperation::visitUnary(Visit visit, TIntermUnary *node)
+{
+ if (mGradientOperation)
+ {
+ return false;
+ }
+
+ switch (node->getOp())
+ {
+ case EOpDFdx:
+ case EOpDFdy:
+ mGradientOperation = true;
+ default:
+ break;
+ }
+
+ return !mGradientOperation;
+}
+
+bool DetectGradientOperation::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ if (mGradientOperation)
+ {
+ return false;
+ }
+
+ if (node->getOp() == EOpFunctionCall)
+ {
+ if (!node->isUserDefined())
+ {
+ TString name = TFunction::unmangleName(node->getName());
+
+ if (name == "texture2D" ||
+ name == "texture2DProj" ||
+ name == "textureCube")
+ {
+ mGradientOperation = true;
+ }
+ }
+ else
+ {
+ // When a user defined function is called, we have to
+ // conservatively assume it to contain gradient operations
+ mGradientOperation = true;
+ }
+ }
+
+ return !mGradientOperation;
+}
+
+bool containsGradientOperation(TIntermNode *node)
+{
+ DetectGradientOperation detectGradientOperation;
+ return detectGradientOperation.traverse(node);
+}
+}
diff --git a/src/compiler/DetectDiscontinuity.h b/src/compiler/DetectDiscontinuity.h
new file mode 100644
index 00000000..e5520bd5
--- /dev/null
+++ b/src/compiler/DetectDiscontinuity.h
@@ -0,0 +1,52 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Contains analysis utilities for dealing with HLSL's lack of support for
+// the use of intrinsic functions which (implicitly or explicitly) compute
+// gradients of functions with discontinuities.
+//
+
+#ifndef COMPILER_DETECTDISCONTINUITY_H_
+#define COMPILER_DETECTDISCONTINUITY_H_
+
+#include "compiler/intermediate.h"
+
+namespace sh
+{
+// Checks whether a loop can run for a variable number of iterations
+class DetectLoopDiscontinuity : public TIntermTraverser
+{
+ public:
+ bool traverse(TIntermNode *node);
+
+ protected:
+ bool visitBranch(Visit visit, TIntermBranch *node);
+ bool visitLoop(Visit visit, TIntermLoop *loop);
+ bool visitAggregate(Visit visit, TIntermAggregate *node);
+
+ int mLoopDepth;
+ bool mLoopDiscontinuity;
+};
+
+bool containsLoopDiscontinuity(TIntermNode *node);
+
+// Checks for intrinsic functions which compute gradients
+class DetectGradientOperation : public TIntermTraverser
+{
+ public:
+ bool traverse(TIntermNode *node);
+
+ protected:
+ bool visitUnary(Visit visit, TIntermUnary *node);
+ bool visitAggregate(Visit visit, TIntermAggregate *node);
+
+ bool mGradientOperation;
+};
+
+bool containsGradientOperation(TIntermNode *node);
+
+}
+
+#endif // COMPILER_DETECTDISCONTINUITY_H_
diff --git a/src/compiler/Diagnostics.cpp b/src/compiler/Diagnostics.cpp
new file mode 100644
index 00000000..8a38c41a
--- /dev/null
+++ b/src/compiler/Diagnostics.cpp
@@ -0,0 +1,63 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/Diagnostics.h"
+
+#include "compiler/debug.h"
+#include "compiler/InfoSink.h"
+#include "compiler/preprocessor/SourceLocation.h"
+
+TDiagnostics::TDiagnostics(TInfoSink& infoSink) :
+ mInfoSink(infoSink),
+ mNumErrors(0),
+ mNumWarnings(0)
+{
+}
+
+TDiagnostics::~TDiagnostics()
+{
+}
+
+void TDiagnostics::writeInfo(Severity severity,
+ const pp::SourceLocation& loc,
+ const std::string& reason,
+ const std::string& token,
+ const std::string& extra)
+{
+ TPrefixType prefix = EPrefixNone;
+ switch (severity)
+ {
+ case ERROR:
+ ++mNumErrors;
+ prefix = EPrefixError;
+ break;
+ case WARNING:
+ ++mNumWarnings;
+ prefix = EPrefixWarning;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ TInfoSinkBase& sink = mInfoSink.info;
+ /* VC++ format: file(linenum) : error #: 'token' : extrainfo */
+ sink.prefix(prefix);
+ sink.location(loc.file, loc.line);
+ sink << "'" << token << "' : " << reason << " " << extra << "\n";
+}
+
+void TDiagnostics::writeDebug(const std::string& str)
+{
+ mInfoSink.debug << str;
+}
+
+void TDiagnostics::print(ID id,
+ const pp::SourceLocation& loc,
+ const std::string& text)
+{
+ writeInfo(severity(id), loc, message(id), text, "");
+}
diff --git a/src/compiler/Diagnostics.h b/src/compiler/Diagnostics.h
new file mode 100644
index 00000000..cb71bb12
--- /dev/null
+++ b/src/compiler/Diagnostics.h
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DIAGNOSTICS_H_
+#define COMPILER_DIAGNOSTICS_H_
+
+#include "compiler/preprocessor/DiagnosticsBase.h"
+
+class TInfoSink;
+
+class TDiagnostics : public pp::Diagnostics
+{
+ public:
+ TDiagnostics(TInfoSink& infoSink);
+ virtual ~TDiagnostics();
+
+ TInfoSink& infoSink() { return mInfoSink; }
+
+ int numErrors() const { return mNumErrors; }
+ int numWarnings() const { return mNumWarnings; }
+
+ void writeInfo(Severity severity,
+ const pp::SourceLocation& loc,
+ const std::string& reason,
+ const std::string& token,
+ const std::string& extra);
+
+ void writeDebug(const std::string& str);
+
+ protected:
+ virtual void print(ID id,
+ const pp::SourceLocation& loc,
+ const std::string& text);
+
+ private:
+ TInfoSink& mInfoSink;
+ int mNumErrors;
+ int mNumWarnings;
+};
+
+#endif // COMPILER_DIAGNOSTICS_H_
diff --git a/src/compiler/DirectiveHandler.cpp b/src/compiler/DirectiveHandler.cpp
new file mode 100644
index 00000000..d1f6ab3a
--- /dev/null
+++ b/src/compiler/DirectiveHandler.cpp
@@ -0,0 +1,161 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/DirectiveHandler.h"
+
+#include <sstream>
+
+#include "compiler/debug.h"
+#include "compiler/Diagnostics.h"
+
+static TBehavior getBehavior(const std::string& str)
+{
+ static const std::string kRequire("require");
+ static const std::string kEnable("enable");
+ static const std::string kDisable("disable");
+ static const std::string kWarn("warn");
+
+ if (str == kRequire) return EBhRequire;
+ else if (str == kEnable) return EBhEnable;
+ else if (str == kDisable) return EBhDisable;
+ else if (str == kWarn) return EBhWarn;
+ return EBhUndefined;
+}
+
+TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior,
+ TDiagnostics& diagnostics)
+ : mExtensionBehavior(extBehavior),
+ mDiagnostics(diagnostics)
+{
+}
+
+TDirectiveHandler::~TDirectiveHandler()
+{
+}
+
+void TDirectiveHandler::handleError(const pp::SourceLocation& loc,
+ const std::string& msg)
+{
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc, msg, "", "");
+}
+
+void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& value)
+{
+ static const std::string kSTDGL("STDGL");
+ static const std::string kOptimize("optimize");
+ static const std::string kDebug("debug");
+ static const std::string kOn("on");
+ static const std::string kOff("off");
+
+ bool invalidValue = false;
+ if (name == kSTDGL)
+ {
+ // The STDGL pragma is used to reserve pragmas for use by future
+ // revisions of GLSL. Ignore it.
+ return;
+ }
+ else if (name == kOptimize)
+ {
+ if (value == kOn) mPragma.optimize = true;
+ else if (value == kOff) mPragma.optimize = false;
+ else invalidValue = true;
+ }
+ else if (name == kDebug)
+ {
+ if (value == kOn) mPragma.debug = true;
+ else if (value == kOff) mPragma.debug = false;
+ else invalidValue = true;
+ }
+ else
+ {
+ mDiagnostics.report(pp::Diagnostics::UNRECOGNIZED_PRAGMA, loc, name);
+ return;
+ }
+
+ if (invalidValue)
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "invalid pragma value", value,
+ "'on' or 'off' expected");
+}
+
+void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior)
+{
+ static const std::string kExtAll("all");
+
+ TBehavior behaviorVal = getBehavior(behavior);
+ if (behaviorVal == EBhUndefined)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "behavior", name, "invalid");
+ return;
+ }
+
+ if (name == kExtAll)
+ {
+ if (behaviorVal == EBhRequire)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "extension", name,
+ "cannot have 'require' behavior");
+ }
+ else if (behaviorVal == EBhEnable)
+ {
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "extension", name,
+ "cannot have 'enable' behavior");
+ }
+ else
+ {
+ for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
+ iter != mExtensionBehavior.end(); ++iter)
+ iter->second = behaviorVal;
+ }
+ return;
+ }
+
+ TExtensionBehavior::iterator iter = mExtensionBehavior.find(name);
+ if (iter != mExtensionBehavior.end())
+ {
+ iter->second = behaviorVal;
+ return;
+ }
+
+ pp::Diagnostics::Severity severity = pp::Diagnostics::ERROR;
+ switch (behaviorVal) {
+ case EBhRequire:
+ severity = pp::Diagnostics::ERROR;
+ break;
+ case EBhEnable:
+ case EBhWarn:
+ case EBhDisable:
+ severity = pp::Diagnostics::WARNING;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ mDiagnostics.writeInfo(severity, loc,
+ "extension", name, "is not supported");
+}
+
+void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc,
+ int version)
+{
+ static const int kVersion = 100;
+
+ if (version != kVersion)
+ {
+ std::stringstream stream;
+ stream << version;
+ std::string str = stream.str();
+ mDiagnostics.writeInfo(pp::Diagnostics::ERROR, loc,
+ "version number", str, "not supported");
+ }
+}
diff --git a/src/compiler/DirectiveHandler.h b/src/compiler/DirectiveHandler.h
new file mode 100644
index 00000000..95ca59d6
--- /dev/null
+++ b/src/compiler/DirectiveHandler.h
@@ -0,0 +1,46 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DIRECTIVE_HANDLER_H_
+#define COMPILER_DIRECTIVE_HANDLER_H_
+
+#include "compiler/ExtensionBehavior.h"
+#include "compiler/Pragma.h"
+#include "compiler/preprocessor/DirectiveHandlerBase.h"
+
+class TDiagnostics;
+
+class TDirectiveHandler : public pp::DirectiveHandler
+{
+ public:
+ TDirectiveHandler(TExtensionBehavior& extBehavior,
+ TDiagnostics& diagnostics);
+ virtual ~TDirectiveHandler();
+
+ const TPragma& pragma() const { return mPragma; }
+ const TExtensionBehavior& extensionBehavior() const { return mExtensionBehavior; }
+
+ virtual void handleError(const pp::SourceLocation& loc,
+ const std::string& msg);
+
+ virtual void handlePragma(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& value);
+
+ virtual void handleExtension(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior);
+
+ virtual void handleVersion(const pp::SourceLocation& loc,
+ int version);
+
+ private:
+ TPragma mPragma;
+ TExtensionBehavior& mExtensionBehavior;
+ TDiagnostics& mDiagnostics;
+};
+
+#endif // COMPILER_DIRECTIVE_HANDLER_H_
diff --git a/src/compiler/ExtensionBehavior.h b/src/compiler/ExtensionBehavior.h
new file mode 100644
index 00000000..5c1595fb
--- /dev/null
+++ b/src/compiler/ExtensionBehavior.h
@@ -0,0 +1,37 @@
+//
+// 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.
+//
+
+#ifndef _EXTENSION_BEHAVIOR_INCLUDED_
+#define _EXTENSION_BEHAVIOR_INCLUDED_
+
+#include <map>
+#include <string>
+
+typedef enum
+{
+ EBhRequire,
+ EBhEnable,
+ EBhWarn,
+ EBhDisable,
+ EBhUndefined
+} TBehavior;
+
+inline const char* getBehaviorString(TBehavior b)
+{
+ switch(b)
+ {
+ case EBhRequire: return "require";
+ case EBhEnable: return "enable";
+ case EBhWarn: return "warn";
+ case EBhDisable: return "disable";
+ default: return NULL;
+ }
+}
+
+// Mapping between extension name and behavior.
+typedef std::map<std::string, TBehavior> TExtensionBehavior;
+
+#endif // _EXTENSION_TABLE_INCLUDED_
diff --git a/src/compiler/ForLoopUnroll.cpp b/src/compiler/ForLoopUnroll.cpp
new file mode 100644
index 00000000..27a13eab
--- /dev/null
+++ b/src/compiler/ForLoopUnroll.cpp
@@ -0,0 +1,215 @@
+//
+// 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.
+//
+
+#include "compiler/ForLoopUnroll.h"
+
+namespace {
+
+class IntegerForLoopUnrollMarker : public TIntermTraverser {
+public:
+
+ virtual bool visitLoop(Visit, TIntermLoop* node)
+ {
+ // This is called after ValidateLimitations pass, so all the ASSERT
+ // should never fail.
+ // See ValidateLimitations::validateForLoopInit().
+ ASSERT(node);
+ ASSERT(node->getType() == ELoopFor);
+ ASSERT(node->getInit());
+ TIntermAggregate* decl = node->getInit()->getAsAggregate();
+ ASSERT(decl && decl->getOp() == EOpDeclaration);
+ TIntermSequence& declSeq = decl->getSequence();
+ ASSERT(declSeq.size() == 1);
+ TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
+ ASSERT(declInit && declInit->getOp() == EOpInitialize);
+ ASSERT(declInit->getLeft());
+ TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
+ ASSERT(symbol);
+ TBasicType type = symbol->getBasicType();
+ ASSERT(type == EbtInt || type == EbtFloat);
+ if (type == EbtInt)
+ node->setUnrollFlag(true);
+ return true;
+ }
+
+};
+
+} // anonymous namepsace
+
+void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info)
+{
+ ASSERT(node->getType() == ELoopFor);
+ ASSERT(node->getUnrollFlag());
+
+ TIntermNode* init = node->getInit();
+ ASSERT(init != NULL);
+ TIntermAggregate* decl = init->getAsAggregate();
+ ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration));
+ TIntermSequence& declSeq = decl->getSequence();
+ ASSERT(declSeq.size() == 1);
+ TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
+ ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize));
+ TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
+ ASSERT(symbol != NULL);
+ ASSERT(symbol->getBasicType() == EbtInt);
+
+ info.id = symbol->getId();
+
+ ASSERT(declInit->getRight() != NULL);
+ TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
+ ASSERT(initNode != NULL);
+
+ info.initValue = evaluateIntConstant(initNode);
+ info.currentValue = info.initValue;
+
+ TIntermNode* cond = node->getCondition();
+ ASSERT(cond != NULL);
+ TIntermBinary* binOp = cond->getAsBinaryNode();
+ ASSERT(binOp != NULL);
+ ASSERT(binOp->getRight() != NULL);
+ ASSERT(binOp->getRight()->getAsConstantUnion() != NULL);
+
+ info.incrementValue = getLoopIncrement(node);
+ info.stopValue = evaluateIntConstant(
+ binOp->getRight()->getAsConstantUnion());
+ info.op = binOp->getOp();
+}
+
+void ForLoopUnroll::Step()
+{
+ ASSERT(mLoopIndexStack.size() > 0);
+ TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
+ info.currentValue += info.incrementValue;
+}
+
+bool ForLoopUnroll::SatisfiesLoopCondition()
+{
+ ASSERT(mLoopIndexStack.size() > 0);
+ TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (info.op) {
+ case EOpEqual:
+ return (info.currentValue == info.stopValue);
+ case EOpNotEqual:
+ return (info.currentValue != info.stopValue);
+ case EOpLessThan:
+ return (info.currentValue < info.stopValue);
+ case EOpGreaterThan:
+ return (info.currentValue > info.stopValue);
+ case EOpLessThanEqual:
+ return (info.currentValue <= info.stopValue);
+ case EOpGreaterThanEqual:
+ return (info.currentValue >= info.stopValue);
+ default:
+ UNREACHABLE();
+ }
+ return false;
+}
+
+bool ForLoopUnroll::NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol)
+{
+ for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
+ i != mLoopIndexStack.end();
+ ++i) {
+ if (i->id == symbol->getId())
+ return true;
+ }
+ return false;
+}
+
+int ForLoopUnroll::GetLoopIndexValue(TIntermSymbol* symbol)
+{
+ for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
+ i != mLoopIndexStack.end();
+ ++i) {
+ if (i->id == symbol->getId())
+ return i->currentValue;
+ }
+ UNREACHABLE();
+ return false;
+}
+
+void ForLoopUnroll::Push(TLoopIndexInfo& info)
+{
+ mLoopIndexStack.push_back(info);
+}
+
+void ForLoopUnroll::Pop()
+{
+ mLoopIndexStack.pop_back();
+}
+
+// static
+void ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(
+ TIntermNode* root)
+{
+ ASSERT(root);
+
+ IntegerForLoopUnrollMarker marker;
+ root->traverse(&marker);
+}
+
+int ForLoopUnroll::getLoopIncrement(TIntermLoop* node)
+{
+ TIntermNode* expr = node->getExpression();
+ ASSERT(expr != NULL);
+ // for expression has one of the following forms:
+ // loop_index++
+ // loop_index--
+ // loop_index += constant_expression
+ // loop_index -= constant_expression
+ // ++loop_index
+ // --loop_index
+ // The last two forms are not specified in the spec, but I am assuming
+ // its an oversight.
+ TIntermUnary* unOp = expr->getAsUnaryNode();
+ TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermConstantUnion* incrementNode = NULL;
+ if (unOp != NULL) {
+ op = unOp->getOp();
+ } else if (binOp != NULL) {
+ op = binOp->getOp();
+ ASSERT(binOp->getRight() != NULL);
+ incrementNode = binOp->getRight()->getAsConstantUnion();
+ ASSERT(incrementNode != NULL);
+ }
+
+ int increment = 0;
+ // The operator is one of: ++ -- += -=.
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ increment = 1;
+ break;
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ increment = -1;
+ break;
+ case EOpAddAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ increment = evaluateIntConstant(incrementNode);
+ break;
+ case EOpSubAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ increment = - evaluateIntConstant(incrementNode);
+ break;
+ default:
+ ASSERT(false);
+ }
+
+ return increment;
+}
+
+int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node)
+{
+ ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL));
+ return node->getIConst(0);
+}
+
diff --git a/src/compiler/ForLoopUnroll.h b/src/compiler/ForLoopUnroll.h
new file mode 100644
index 00000000..e800e25b
--- /dev/null
+++ b/src/compiler/ForLoopUnroll.h
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/intermediate.h"
+
+struct TLoopIndexInfo {
+ int id;
+ int initValue;
+ int stopValue;
+ int incrementValue;
+ TOperator op;
+ int currentValue;
+};
+
+class ForLoopUnroll {
+public:
+ ForLoopUnroll() { }
+
+ void FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info);
+
+ // Update the info.currentValue for the next loop iteration.
+ void Step();
+
+ // Return false if loop condition is no longer satisfied.
+ bool SatisfiesLoopCondition();
+
+ // Check if the symbol is the index of a loop that's unrolled.
+ bool NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol);
+
+ // Return the current value of a given loop index symbol.
+ int GetLoopIndexValue(TIntermSymbol* symbol);
+
+ void Push(TLoopIndexInfo& info);
+ void Pop();
+
+ static void MarkForLoopsWithIntegerIndicesForUnrolling(TIntermNode* root);
+
+private:
+ int getLoopIncrement(TIntermLoop* node);
+
+ int evaluateIntConstant(TIntermConstantUnion* node);
+
+ TVector<TLoopIndexInfo> mLoopIndexStack;
+};
+
diff --git a/src/compiler/HashNames.h b/src/compiler/HashNames.h
new file mode 100644
index 00000000..d2141e2d
--- /dev/null
+++ b/src/compiler/HashNames.h
@@ -0,0 +1,19 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_HASH_NAMES_H_
+#define COMPILER_HASH_NAMES_H_
+
+#include <map>
+
+#include "compiler/intermediate.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define HASHED_NAME_PREFIX "webgl_"
+
+typedef std::map<TPersistString, TPersistString> NameMap;
+
+#endif // COMPILER_HASH_NAMES_H_
diff --git a/src/compiler/InfoSink.cpp b/src/compiler/InfoSink.cpp
new file mode 100644
index 00000000..d20a6c01
--- /dev/null
+++ b/src/compiler/InfoSink.cpp
@@ -0,0 +1,54 @@
+//
+// 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.
+//
+
+#include "compiler/InfoSink.h"
+
+void TInfoSinkBase::prefix(TPrefixType p) {
+ switch(p) {
+ case EPrefixNone:
+ break;
+ case EPrefixWarning:
+ sink.append("WARNING: ");
+ break;
+ case EPrefixError:
+ sink.append("ERROR: ");
+ break;
+ case EPrefixInternalError:
+ sink.append("INTERNAL ERROR: ");
+ break;
+ case EPrefixUnimplemented:
+ sink.append("UNIMPLEMENTED: ");
+ break;
+ case EPrefixNote:
+ sink.append("NOTE: ");
+ break;
+ default:
+ sink.append("UNKOWN ERROR: ");
+ break;
+ }
+}
+
+void TInfoSinkBase::location(int file, int line) {
+ TPersistStringStream stream;
+ if (line)
+ stream << file << ":" << line;
+ else
+ stream << file << ":? ";
+ stream << ": ";
+
+ sink.append(stream.str());
+}
+
+void TInfoSinkBase::location(const TSourceLoc& loc) {
+ location(loc.first_file, loc.first_line);
+}
+
+void TInfoSinkBase::message(TPrefixType p, const TSourceLoc& loc, const char* m) {
+ prefix(p);
+ location(loc);
+ sink.append(m);
+ sink.append("\n");
+}
diff --git a/src/compiler/InfoSink.h b/src/compiler/InfoSink.h
new file mode 100644
index 00000000..68888381
--- /dev/null
+++ b/src/compiler/InfoSink.h
@@ -0,0 +1,115 @@
+//
+// 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.
+//
+
+#ifndef _INFOSINK_INCLUDED_
+#define _INFOSINK_INCLUDED_
+
+#include <math.h>
+#include "compiler/Common.h"
+
+// Returns the fractional part of the given floating-point number.
+inline float fractionalPart(float f) {
+ float intPart = 0.0f;
+ return modff(f, &intPart);
+}
+
+//
+// TPrefixType is used to centralize how info log messages start.
+// See below.
+//
+enum TPrefixType {
+ EPrefixNone,
+ EPrefixWarning,
+ EPrefixError,
+ EPrefixInternalError,
+ EPrefixUnimplemented,
+ EPrefixNote
+};
+
+//
+// Encapsulate info logs for all objects that have them.
+//
+// The methods are a general set of tools for getting a variety of
+// messages and types inserted into the log.
+//
+class TInfoSinkBase {
+public:
+ TInfoSinkBase() {}
+
+ template <typename T>
+ TInfoSinkBase& operator<<(const T& t) {
+ TPersistStringStream stream;
+ stream << t;
+ sink.append(stream.str());
+ return *this;
+ }
+ // Override << operator for specific types. It is faster to append strings
+ // and characters directly to the sink.
+ TInfoSinkBase& operator<<(char c) {
+ sink.append(1, c);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const char* str) {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const TPersistString& str) {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const TString& str) {
+ sink.append(str.c_str());
+ return *this;
+ }
+ // Make sure floats are written with correct precision.
+ TInfoSinkBase& operator<<(float f) {
+ // Make sure that at least one decimal point is written. If a number
+ // does not have a fractional part, the default precision format does
+ // not write the decimal portion which gets interpreted as integer by
+ // the compiler.
+ TPersistStringStream stream;
+ if (fractionalPart(f) == 0.0f) {
+ stream.precision(1);
+ stream << std::showpoint << std::fixed << f;
+ } else {
+ stream.unsetf(std::ios::fixed);
+ stream.unsetf(std::ios::scientific);
+ stream.precision(8);
+ stream << f;
+ }
+ sink.append(stream.str());
+ return *this;
+ }
+ // Write boolean values as their names instead of integral value.
+ TInfoSinkBase& operator<<(bool b) {
+ const char* str = b ? "true" : "false";
+ sink.append(str);
+ return *this;
+ }
+
+ void erase() { sink.clear(); }
+ int size() { return static_cast<int>(sink.size()); }
+
+ const TPersistString& str() const { return sink; }
+ const char* c_str() const { return sink.c_str(); }
+
+ void prefix(TPrefixType p);
+ void location(int file, int line);
+ void location(const TSourceLoc& loc);
+ void message(TPrefixType p, const TSourceLoc& loc, const char* m);
+
+private:
+ TPersistString sink;
+};
+
+class TInfoSink {
+public:
+ TInfoSinkBase info;
+ TInfoSinkBase debug;
+ TInfoSinkBase obj;
+};
+
+#endif // _INFOSINK_INCLUDED_
diff --git a/src/compiler/Initialize.cpp b/src/compiler/Initialize.cpp
new file mode 100644
index 00000000..2cdbe17a
--- /dev/null
+++ b/src/compiler/Initialize.cpp
@@ -0,0 +1,564 @@
+//
+// 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.
+//
+
+//
+// Create strings that declare built-in definitions, add built-ins that
+// cannot be expressed in the files, and establish mappings between
+// built-in functions and operators.
+//
+
+#include "compiler/Initialize.h"
+
+#include "compiler/intermediate.h"
+
+void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &symbolTable)
+{
+ TType *float1 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 1);
+ TType *float2 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 2);
+ TType *float3 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 3);
+ TType *float4 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 4);
+
+ TType *int2 = new TType(EbtInt, EbpUndefined, EvqGlobal, 2);
+ TType *int3 = new TType(EbtInt, EbpUndefined, EvqGlobal, 3);
+ TType *int4 = new TType(EbtInt, EbpUndefined, EvqGlobal, 4);
+
+ //
+ // Angle and Trigonometric Functions.
+ //
+ symbolTable.insertBuiltIn(float1, "radians", float1);
+ symbolTable.insertBuiltIn(float2, "radians", float2);
+ symbolTable.insertBuiltIn(float3, "radians", float3);
+ symbolTable.insertBuiltIn(float4, "radians", float4);
+
+ symbolTable.insertBuiltIn(float1, "degrees", float1);
+ symbolTable.insertBuiltIn(float2, "degrees", float2);
+ symbolTable.insertBuiltIn(float3, "degrees", float3);
+ symbolTable.insertBuiltIn(float4, "degrees", float4);
+
+ symbolTable.insertBuiltIn(float1, "sin", float1);
+ symbolTable.insertBuiltIn(float2, "sin", float2);
+ symbolTable.insertBuiltIn(float3, "sin", float3);
+ symbolTable.insertBuiltIn(float4, "sin", float4);
+
+ symbolTable.insertBuiltIn(float1, "cos", float1);
+ symbolTable.insertBuiltIn(float2, "cos", float2);
+ symbolTable.insertBuiltIn(float3, "cos", float3);
+ symbolTable.insertBuiltIn(float4, "cos", float4);
+
+ symbolTable.insertBuiltIn(float1, "tan", float1);
+ symbolTable.insertBuiltIn(float2, "tan", float2);
+ symbolTable.insertBuiltIn(float3, "tan", float3);
+ symbolTable.insertBuiltIn(float4, "tan", float4);
+
+ symbolTable.insertBuiltIn(float1, "asin", float1);
+ symbolTable.insertBuiltIn(float2, "asin", float2);
+ symbolTable.insertBuiltIn(float3, "asin", float3);
+ symbolTable.insertBuiltIn(float4, "asin", float4);
+
+ symbolTable.insertBuiltIn(float1, "acos", float1);
+ symbolTable.insertBuiltIn(float2, "acos", float2);
+ symbolTable.insertBuiltIn(float3, "acos", float3);
+ symbolTable.insertBuiltIn(float4, "acos", float4);
+
+ symbolTable.insertBuiltIn(float1, "atan", float1, float1);
+ symbolTable.insertBuiltIn(float2, "atan", float2, float2);
+ symbolTable.insertBuiltIn(float3, "atan", float3, float3);
+ symbolTable.insertBuiltIn(float4, "atan", float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "atan", float1);
+ symbolTable.insertBuiltIn(float2, "atan", float2);
+ symbolTable.insertBuiltIn(float3, "atan", float3);
+ symbolTable.insertBuiltIn(float4, "atan", float4);
+
+ //
+ // Exponential Functions.
+ //
+ symbolTable.insertBuiltIn(float1, "pow", float1, float1);
+ symbolTable.insertBuiltIn(float2, "pow", float2, float2);
+ symbolTable.insertBuiltIn(float3, "pow", float3, float3);
+ symbolTable.insertBuiltIn(float4, "pow", float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "exp", float1);
+ symbolTable.insertBuiltIn(float2, "exp", float2);
+ symbolTable.insertBuiltIn(float3, "exp", float3);
+ symbolTable.insertBuiltIn(float4, "exp", float4);
+
+ symbolTable.insertBuiltIn(float1, "log", float1);
+ symbolTable.insertBuiltIn(float2, "log", float2);
+ symbolTable.insertBuiltIn(float3, "log", float3);
+ symbolTable.insertBuiltIn(float4, "log", float4);
+
+ symbolTable.insertBuiltIn(float1, "exp2", float1);
+ symbolTable.insertBuiltIn(float2, "exp2", float2);
+ symbolTable.insertBuiltIn(float3, "exp2", float3);
+ symbolTable.insertBuiltIn(float4, "exp2", float4);
+
+ symbolTable.insertBuiltIn(float1, "log2", float1);
+ symbolTable.insertBuiltIn(float2, "log2", float2);
+ symbolTable.insertBuiltIn(float3, "log2", float3);
+ symbolTable.insertBuiltIn(float4, "log2", float4);
+
+ symbolTable.insertBuiltIn(float1, "sqrt", float1);
+ symbolTable.insertBuiltIn(float2, "sqrt", float2);
+ symbolTable.insertBuiltIn(float3, "sqrt", float3);
+ symbolTable.insertBuiltIn(float4, "sqrt", float4);
+
+ symbolTable.insertBuiltIn(float1, "inversesqrt", float1);
+ symbolTable.insertBuiltIn(float2, "inversesqrt", float2);
+ symbolTable.insertBuiltIn(float3, "inversesqrt", float3);
+ symbolTable.insertBuiltIn(float4, "inversesqrt", float4);
+
+ //
+ // Common Functions.
+ //
+ symbolTable.insertBuiltIn(float1, "abs", float1);
+ symbolTable.insertBuiltIn(float2, "abs", float2);
+ symbolTable.insertBuiltIn(float3, "abs", float3);
+ symbolTable.insertBuiltIn(float4, "abs", float4);
+
+ symbolTable.insertBuiltIn(float1, "sign", float1);
+ symbolTable.insertBuiltIn(float2, "sign", float2);
+ symbolTable.insertBuiltIn(float3, "sign", float3);
+ symbolTable.insertBuiltIn(float4, "sign", float4);
+
+ symbolTable.insertBuiltIn(float1, "floor", float1);
+ symbolTable.insertBuiltIn(float2, "floor", float2);
+ symbolTable.insertBuiltIn(float3, "floor", float3);
+ symbolTable.insertBuiltIn(float4, "floor", float4);
+
+ symbolTable.insertBuiltIn(float1, "ceil", float1);
+ symbolTable.insertBuiltIn(float2, "ceil", float2);
+ symbolTable.insertBuiltIn(float3, "ceil", float3);
+ symbolTable.insertBuiltIn(float4, "ceil", float4);
+
+ symbolTable.insertBuiltIn(float1, "fract", float1);
+ symbolTable.insertBuiltIn(float2, "fract", float2);
+ symbolTable.insertBuiltIn(float3, "fract", float3);
+ symbolTable.insertBuiltIn(float4, "fract", float4);
+
+ symbolTable.insertBuiltIn(float1, "mod", float1, float1);
+ symbolTable.insertBuiltIn(float2, "mod", float2, float1);
+ symbolTable.insertBuiltIn(float3, "mod", float3, float1);
+ symbolTable.insertBuiltIn(float4, "mod", float4, float1);
+ symbolTable.insertBuiltIn(float2, "mod", float2, float2);
+ symbolTable.insertBuiltIn(float3, "mod", float3, float3);
+ symbolTable.insertBuiltIn(float4, "mod", float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "min", float1, float1);
+ symbolTable.insertBuiltIn(float2, "min", float2, float1);
+ symbolTable.insertBuiltIn(float3, "min", float3, float1);
+ symbolTable.insertBuiltIn(float4, "min", float4, float1);
+ symbolTable.insertBuiltIn(float2, "min", float2, float2);
+ symbolTable.insertBuiltIn(float3, "min", float3, float3);
+ symbolTable.insertBuiltIn(float4, "min", float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "max", float1, float1);
+ symbolTable.insertBuiltIn(float2, "max", float2, float1);
+ symbolTable.insertBuiltIn(float3, "max", float3, float1);
+ symbolTable.insertBuiltIn(float4, "max", float4, float1);
+ symbolTable.insertBuiltIn(float2, "max", float2, float2);
+ symbolTable.insertBuiltIn(float3, "max", float3, float3);
+ symbolTable.insertBuiltIn(float4, "max", float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "clamp", float1, float1, float1);
+ symbolTable.insertBuiltIn(float2, "clamp", float2, float1, float1);
+ symbolTable.insertBuiltIn(float3, "clamp", float3, float1, float1);
+ symbolTable.insertBuiltIn(float4, "clamp", float4, float1, float1);
+ symbolTable.insertBuiltIn(float2, "clamp", float2, float2, float2);
+ symbolTable.insertBuiltIn(float3, "clamp", float3, float3, float3);
+ symbolTable.insertBuiltIn(float4, "clamp", float4, float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "mix", float1, float1, float1);
+ symbolTable.insertBuiltIn(float2, "mix", float2, float2, float1);
+ symbolTable.insertBuiltIn(float3, "mix", float3, float3, float1);
+ symbolTable.insertBuiltIn(float4, "mix", float4, float4, float1);
+ symbolTable.insertBuiltIn(float2, "mix", float2, float2, float2);
+ symbolTable.insertBuiltIn(float3, "mix", float3, float3, float3);
+ symbolTable.insertBuiltIn(float4, "mix", float4, float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "step", float1, float1);
+ symbolTable.insertBuiltIn(float2, "step", float2, float2);
+ symbolTable.insertBuiltIn(float3, "step", float3, float3);
+ symbolTable.insertBuiltIn(float4, "step", float4, float4);
+ symbolTable.insertBuiltIn(float2, "step", float1, float2);
+ symbolTable.insertBuiltIn(float3, "step", float1, float3);
+ symbolTable.insertBuiltIn(float4, "step", float1, float4);
+
+ symbolTable.insertBuiltIn(float1, "smoothstep", float1, float1, float1);
+ symbolTable.insertBuiltIn(float2, "smoothstep", float2, float2, float2);
+ symbolTable.insertBuiltIn(float3, "smoothstep", float3, float3, float3);
+ symbolTable.insertBuiltIn(float4, "smoothstep", float4, float4, float4);
+ symbolTable.insertBuiltIn(float2, "smoothstep", float1, float1, float2);
+ symbolTable.insertBuiltIn(float3, "smoothstep", float1, float1, float3);
+ symbolTable.insertBuiltIn(float4, "smoothstep", float1, float1, float4);
+
+ //
+ // Geometric Functions.
+ //
+ symbolTable.insertBuiltIn(float1, "length", float1);
+ symbolTable.insertBuiltIn(float1, "length", float2);
+ symbolTable.insertBuiltIn(float1, "length", float3);
+ symbolTable.insertBuiltIn(float1, "length", float4);
+
+ symbolTable.insertBuiltIn(float1, "distance", float1, float1);
+ symbolTable.insertBuiltIn(float1, "distance", float2, float2);
+ symbolTable.insertBuiltIn(float1, "distance", float3, float3);
+ symbolTable.insertBuiltIn(float1, "distance", float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "dot", float1, float1);
+ symbolTable.insertBuiltIn(float1, "dot", float2, float2);
+ symbolTable.insertBuiltIn(float1, "dot", float3, float3);
+ symbolTable.insertBuiltIn(float1, "dot", float4, float4);
+
+ symbolTable.insertBuiltIn(float3, "cross", float3, float3);
+ symbolTable.insertBuiltIn(float1, "normalize", float1);
+ symbolTable.insertBuiltIn(float2, "normalize", float2);
+ symbolTable.insertBuiltIn(float3, "normalize", float3);
+ symbolTable.insertBuiltIn(float4, "normalize", float4);
+
+ symbolTable.insertBuiltIn(float1, "faceforward", float1, float1, float1);
+ symbolTable.insertBuiltIn(float2, "faceforward", float2, float2, float2);
+ symbolTable.insertBuiltIn(float3, "faceforward", float3, float3, float3);
+ symbolTable.insertBuiltIn(float4, "faceforward", float4, float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "reflect", float1, float1);
+ symbolTable.insertBuiltIn(float2, "reflect", float2, float2);
+ symbolTable.insertBuiltIn(float3, "reflect", float3, float3);
+ symbolTable.insertBuiltIn(float4, "reflect", float4, float4);
+
+ symbolTable.insertBuiltIn(float1, "refract", float1, float1, float1);
+ symbolTable.insertBuiltIn(float2, "refract", float2, float2, float1);
+ symbolTable.insertBuiltIn(float3, "refract", float3, float3, float1);
+ symbolTable.insertBuiltIn(float4, "refract", float4, float4, float1);
+
+ TType *mat2 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 2, true);
+ TType *mat3 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 3, true);
+ TType *mat4 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 4, true);
+
+ //
+ // Matrix Functions.
+ //
+ symbolTable.insertBuiltIn(mat2, "matrixCompMult", mat2, mat2);
+ symbolTable.insertBuiltIn(mat3, "matrixCompMult", mat3, mat3);
+ symbolTable.insertBuiltIn(mat4, "matrixCompMult", mat4, mat4);
+
+ TType *bool1 = new TType(EbtBool, EbpUndefined, EvqGlobal, 1);
+ TType *bool2 = new TType(EbtBool, EbpUndefined, EvqGlobal, 2);
+ TType *bool3 = new TType(EbtBool, EbpUndefined, EvqGlobal, 3);
+ TType *bool4 = new TType(EbtBool, EbpUndefined, EvqGlobal, 4);
+
+ //
+ // Vector relational functions.
+ //
+ symbolTable.insertBuiltIn(bool2, "lessThan", float2, float2);
+ symbolTable.insertBuiltIn(bool3, "lessThan", float3, float3);
+ symbolTable.insertBuiltIn(bool4, "lessThan", float4, float4);
+
+ symbolTable.insertBuiltIn(bool2, "lessThan", int2, int2);
+ symbolTable.insertBuiltIn(bool3, "lessThan", int3, int3);
+ symbolTable.insertBuiltIn(bool4, "lessThan", int4, int4);
+
+ symbolTable.insertBuiltIn(bool2, "lessThanEqual", float2, float2);
+ symbolTable.insertBuiltIn(bool3, "lessThanEqual", float3, float3);
+ symbolTable.insertBuiltIn(bool4, "lessThanEqual", float4, float4);
+
+ symbolTable.insertBuiltIn(bool2, "lessThanEqual", int2, int2);
+ symbolTable.insertBuiltIn(bool3, "lessThanEqual", int3, int3);
+ symbolTable.insertBuiltIn(bool4, "lessThanEqual", int4, int4);
+
+ symbolTable.insertBuiltIn(bool2, "greaterThan", float2, float2);
+ symbolTable.insertBuiltIn(bool3, "greaterThan", float3, float3);
+ symbolTable.insertBuiltIn(bool4, "greaterThan", float4, float4);
+
+ symbolTable.insertBuiltIn(bool2, "greaterThan", int2, int2);
+ symbolTable.insertBuiltIn(bool3, "greaterThan", int3, int3);
+ symbolTable.insertBuiltIn(bool4, "greaterThan", int4, int4);
+
+ symbolTable.insertBuiltIn(bool2, "greaterThanEqual", float2, float2);
+ symbolTable.insertBuiltIn(bool3, "greaterThanEqual", float3, float3);
+ symbolTable.insertBuiltIn(bool4, "greaterThanEqual", float4, float4);
+
+ symbolTable.insertBuiltIn(bool2, "greaterThanEqual", int2, int2);
+ symbolTable.insertBuiltIn(bool3, "greaterThanEqual", int3, int3);
+ symbolTable.insertBuiltIn(bool4, "greaterThanEqual", int4, int4);
+
+ symbolTable.insertBuiltIn(bool2, "equal", float2, float2);
+ symbolTable.insertBuiltIn(bool3, "equal", float3, float3);
+ symbolTable.insertBuiltIn(bool4, "equal", float4, float4);
+
+ symbolTable.insertBuiltIn(bool2, "equal", int2, int2);
+ symbolTable.insertBuiltIn(bool3, "equal", int3, int3);
+ symbolTable.insertBuiltIn(bool4, "equal", int4, int4);
+
+ symbolTable.insertBuiltIn(bool2, "equal", bool2, bool2);
+ symbolTable.insertBuiltIn(bool3, "equal", bool3, bool3);
+ symbolTable.insertBuiltIn(bool4, "equal", bool4, bool4);
+
+ symbolTable.insertBuiltIn(bool2, "notEqual", float2, float2);
+ symbolTable.insertBuiltIn(bool3, "notEqual", float3, float3);
+ symbolTable.insertBuiltIn(bool4, "notEqual", float4, float4);
+
+ symbolTable.insertBuiltIn(bool2, "notEqual", int2, int2);
+ symbolTable.insertBuiltIn(bool3, "notEqual", int3, int3);
+ symbolTable.insertBuiltIn(bool4, "notEqual", int4, int4);
+
+ symbolTable.insertBuiltIn(bool2, "notEqual", bool2, bool2);
+ symbolTable.insertBuiltIn(bool3, "notEqual", bool3, bool3);
+ symbolTable.insertBuiltIn(bool4, "notEqual", bool4, bool4);
+
+ symbolTable.insertBuiltIn(bool1, "any", bool2);
+ symbolTable.insertBuiltIn(bool1, "any", bool3);
+ symbolTable.insertBuiltIn(bool1, "any", bool4);
+
+ symbolTable.insertBuiltIn(bool1, "all", bool2);
+ symbolTable.insertBuiltIn(bool1, "all", bool3);
+ symbolTable.insertBuiltIn(bool1, "all", bool4);
+
+ symbolTable.insertBuiltIn(bool2, "not", bool2);
+ symbolTable.insertBuiltIn(bool3, "not", bool3);
+ symbolTable.insertBuiltIn(bool4, "not", bool4);
+
+ TType *sampler2D = new TType(EbtSampler2D, EbpUndefined, EvqGlobal, 1);
+ TType *samplerCube = new TType(EbtSamplerCube, EbpUndefined, EvqGlobal, 1);
+
+ //
+ // Texture Functions for GLSL ES 1.0
+ //
+ symbolTable.insertBuiltIn(float4, "texture2D", sampler2D, float2);
+ symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float3);
+ symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float4);
+ symbolTable.insertBuiltIn(float4, "textureCube", samplerCube, float3);
+
+ if (resources.OES_EGL_image_external)
+ {
+ TType *samplerExternalOES = new TType(EbtSamplerExternalOES, EbpUndefined, EvqGlobal, 1);
+
+ symbolTable.insertBuiltIn(float4, "texture2D", samplerExternalOES, float2);
+ symbolTable.insertBuiltIn(float4, "texture2DProj", samplerExternalOES, float3);
+ symbolTable.insertBuiltIn(float4, "texture2DProj", samplerExternalOES, float4);
+ }
+
+ if (resources.ARB_texture_rectangle)
+ {
+ TType *sampler2DRect = new TType(EbtSampler2DRect, EbpUndefined, EvqGlobal, 1);
+
+ symbolTable.insertBuiltIn(float4, "texture2DRect", sampler2DRect, float2);
+ symbolTable.insertBuiltIn(float4, "texture2DRectProj", sampler2DRect, float3);
+ symbolTable.insertBuiltIn(float4, "texture2DRectProj", sampler2DRect, float4);
+ }
+
+ if (type == SH_FRAGMENT_SHADER)
+ {
+ symbolTable.insertBuiltIn(float4, "texture2D", sampler2D, float2, float1);
+ symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float3, float1);
+ symbolTable.insertBuiltIn(float4, "texture2DProj", sampler2D, float4, float1);
+ symbolTable.insertBuiltIn(float4, "textureCube", samplerCube, float3, float1);
+
+ if (resources.OES_standard_derivatives)
+ {
+ symbolTable.insertBuiltIn(float1, "dFdx", float1);
+ symbolTable.insertBuiltIn(float2, "dFdx", float2);
+ symbolTable.insertBuiltIn(float3, "dFdx", float3);
+ symbolTable.insertBuiltIn(float4, "dFdx", float4);
+
+ symbolTable.insertBuiltIn(float1, "dFdy", float1);
+ symbolTable.insertBuiltIn(float2, "dFdy", float2);
+ symbolTable.insertBuiltIn(float3, "dFdy", float3);
+ symbolTable.insertBuiltIn(float4, "dFdy", float4);
+
+ symbolTable.insertBuiltIn(float1, "fwidth", float1);
+ symbolTable.insertBuiltIn(float2, "fwidth", float2);
+ symbolTable.insertBuiltIn(float3, "fwidth", float3);
+ symbolTable.insertBuiltIn(float4, "fwidth", float4);
+ }
+ }
+
+ if(type == SH_VERTEX_SHADER)
+ {
+ symbolTable.insertBuiltIn(float4, "texture2DLod", sampler2D, float2, float1);
+ symbolTable.insertBuiltIn(float4, "texture2DProjLod", sampler2D, float3, float1);
+ symbolTable.insertBuiltIn(float4, "texture2DProjLod", sampler2D, float4, float1);
+ symbolTable.insertBuiltIn(float4, "textureCubeLod", samplerCube, float3, float1);
+ }
+
+ //
+ // Depth range in window coordinates
+ //
+ TFieldList *fields = NewPoolTFieldList();
+ TField *near = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("near"));
+ TField *far = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("far"));
+ TField *diff = new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1), NewPoolTString("diff"));
+ fields->push_back(near);
+ fields->push_back(far);
+ fields->push_back(diff);
+ TStructure *depthRangeStruct = new TStructure(NewPoolTString("gl_DepthRangeParameters"), fields);
+ TVariable *depthRangeParameters = new TVariable(&depthRangeStruct->name(), depthRangeStruct, true);
+ symbolTable.insert(*depthRangeParameters);
+ TVariable *depthRange = new TVariable(NewPoolTString("gl_DepthRange"), TType(depthRangeStruct));
+ depthRange->setQualifier(EvqUniform);
+ symbolTable.insert(*depthRange);
+
+ //
+ // Implementation dependent built-in constants.
+ //
+ symbolTable.insertConstInt("gl_MaxVertexAttribs", resources.MaxVertexAttribs);
+ symbolTable.insertConstInt("gl_MaxVertexUniformVectors", resources.MaxVertexUniformVectors);
+ symbolTable.insertConstInt("gl_MaxVaryingVectors", resources.MaxVaryingVectors);
+ symbolTable.insertConstInt("gl_MaxVertexTextureImageUnits", resources.MaxVertexTextureImageUnits);
+ symbolTable.insertConstInt("gl_MaxCombinedTextureImageUnits", resources.MaxCombinedTextureImageUnits);
+ symbolTable.insertConstInt("gl_MaxTextureImageUnits", resources.MaxTextureImageUnits);
+ symbolTable.insertConstInt("gl_MaxFragmentUniformVectors", resources.MaxFragmentUniformVectors);
+
+ if (spec != SH_CSS_SHADERS_SPEC)
+ {
+ symbolTable.insertConstInt("gl_MaxDrawBuffers", resources.MaxDrawBuffers);
+ }
+}
+
+void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources &resources,
+ TSymbolTable &symbolTable)
+{
+ //
+ // First, insert some special built-in variables that are not in
+ // the built-in header files.
+ //
+ switch(type) {
+ case SH_FRAGMENT_SHADER:
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
+
+ //
+ // In CSS Shaders, gl_FragColor, gl_FragData, and gl_MaxDrawBuffers are not available.
+ // Instead, css_MixColor and css_ColorMatrix are available.
+ //
+ if (spec != SH_CSS_SHADERS_SPEC) {
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4)));
+ if (resources.EXT_frag_depth) {
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1)));
+ symbolTable.relateToExtension("gl_FragDepthEXT", "GL_EXT_frag_depth");
+ }
+ } else {
+ symbolTable.insert(*new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("css_ColorMatrix"), TType(EbtFloat, EbpMedium, EvqGlobal, 4, true)));
+ }
+
+ break;
+
+ case SH_VERTEX_SHADER:
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1)));
+ break;
+
+ default: assert(false && "Language not supported");
+ }
+
+ //
+ // Next, identify which built-ins from the already loaded headers have
+ // a mapping to an operator. Those that are not identified as such are
+ // expected to be resolved through a library of functions, versus as
+ // operations.
+ //
+ symbolTable.relateToOperator("matrixCompMult", EOpMul);
+
+ symbolTable.relateToOperator("equal", EOpVectorEqual);
+ symbolTable.relateToOperator("notEqual", EOpVectorNotEqual);
+ symbolTable.relateToOperator("lessThan", EOpLessThan);
+ symbolTable.relateToOperator("greaterThan", EOpGreaterThan);
+ symbolTable.relateToOperator("lessThanEqual", EOpLessThanEqual);
+ symbolTable.relateToOperator("greaterThanEqual", EOpGreaterThanEqual);
+
+ symbolTable.relateToOperator("radians", EOpRadians);
+ symbolTable.relateToOperator("degrees", EOpDegrees);
+ symbolTable.relateToOperator("sin", EOpSin);
+ symbolTable.relateToOperator("cos", EOpCos);
+ symbolTable.relateToOperator("tan", EOpTan);
+ symbolTable.relateToOperator("asin", EOpAsin);
+ symbolTable.relateToOperator("acos", EOpAcos);
+ symbolTable.relateToOperator("atan", EOpAtan);
+
+ symbolTable.relateToOperator("pow", EOpPow);
+ symbolTable.relateToOperator("exp2", EOpExp2);
+ symbolTable.relateToOperator("log", EOpLog);
+ symbolTable.relateToOperator("exp", EOpExp);
+ symbolTable.relateToOperator("log2", EOpLog2);
+ symbolTable.relateToOperator("sqrt", EOpSqrt);
+ symbolTable.relateToOperator("inversesqrt", EOpInverseSqrt);
+
+ symbolTable.relateToOperator("abs", EOpAbs);
+ symbolTable.relateToOperator("sign", EOpSign);
+ symbolTable.relateToOperator("floor", EOpFloor);
+ symbolTable.relateToOperator("ceil", EOpCeil);
+ symbolTable.relateToOperator("fract", EOpFract);
+ symbolTable.relateToOperator("mod", EOpMod);
+ symbolTable.relateToOperator("min", EOpMin);
+ symbolTable.relateToOperator("max", EOpMax);
+ symbolTable.relateToOperator("clamp", EOpClamp);
+ symbolTable.relateToOperator("mix", EOpMix);
+ symbolTable.relateToOperator("step", EOpStep);
+ symbolTable.relateToOperator("smoothstep", EOpSmoothStep);
+
+ symbolTable.relateToOperator("length", EOpLength);
+ symbolTable.relateToOperator("distance", EOpDistance);
+ symbolTable.relateToOperator("dot", EOpDot);
+ symbolTable.relateToOperator("cross", EOpCross);
+ symbolTable.relateToOperator("normalize", EOpNormalize);
+ symbolTable.relateToOperator("faceforward", EOpFaceForward);
+ symbolTable.relateToOperator("reflect", EOpReflect);
+ symbolTable.relateToOperator("refract", EOpRefract);
+
+ symbolTable.relateToOperator("any", EOpAny);
+ symbolTable.relateToOperator("all", EOpAll);
+ symbolTable.relateToOperator("not", EOpVectorLogicalNot);
+
+ // Map language-specific operators.
+ switch(type) {
+ case SH_VERTEX_SHADER:
+ break;
+ case SH_FRAGMENT_SHADER:
+ if (resources.OES_standard_derivatives) {
+ symbolTable.relateToOperator("dFdx", EOpDFdx);
+ symbolTable.relateToOperator("dFdy", EOpDFdy);
+ symbolTable.relateToOperator("fwidth", EOpFwidth);
+
+ symbolTable.relateToExtension("dFdx", "GL_OES_standard_derivatives");
+ symbolTable.relateToExtension("dFdy", "GL_OES_standard_derivatives");
+ symbolTable.relateToExtension("fwidth", "GL_OES_standard_derivatives");
+ }
+ break;
+ default: break;
+ }
+
+ // Finally add resource-specific variables.
+ switch(type) {
+ case SH_FRAGMENT_SHADER:
+ if (spec != SH_CSS_SHADERS_SPEC) {
+ // Set up gl_FragData. The array size.
+ TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, false, true);
+ fragData.setArraySize(resources.MaxDrawBuffers);
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData));
+ }
+ break;
+ default: break;
+ }
+}
+
+void InitExtensionBehavior(const ShBuiltInResources& resources,
+ TExtensionBehavior& extBehavior)
+{
+ if (resources.OES_standard_derivatives)
+ extBehavior["GL_OES_standard_derivatives"] = EBhUndefined;
+ if (resources.OES_EGL_image_external)
+ extBehavior["GL_OES_EGL_image_external"] = EBhUndefined;
+ if (resources.ARB_texture_rectangle)
+ extBehavior["GL_ARB_texture_rectangle"] = EBhUndefined;
+ if (resources.EXT_draw_buffers)
+ extBehavior["GL_EXT_draw_buffers"] = EBhUndefined;
+ if (resources.EXT_frag_depth)
+ extBehavior["GL_EXT_frag_depth"] = EBhUndefined;
+}
diff --git a/src/compiler/Initialize.h b/src/compiler/Initialize.h
new file mode 100644
index 00000000..4aa13466
--- /dev/null
+++ b/src/compiler/Initialize.h
@@ -0,0 +1,23 @@
+//
+// 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.
+//
+
+#ifndef _INITIALIZE_INCLUDED_
+#define _INITIALIZE_INCLUDED_
+
+#include "compiler/Common.h"
+#include "compiler/ShHandle.h"
+#include "compiler/SymbolTable.h"
+
+void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltInResources &resources, TSymbolTable &table);
+
+void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources,
+ TSymbolTable& symbolTable);
+
+void InitExtensionBehavior(const ShBuiltInResources& resources,
+ TExtensionBehavior& extensionBehavior);
+
+#endif // _INITIALIZE_INCLUDED_
diff --git a/src/compiler/InitializeDll.cpp b/src/compiler/InitializeDll.cpp
new file mode 100644
index 00000000..6c7f27fc
--- /dev/null
+++ b/src/compiler/InitializeDll.cpp
@@ -0,0 +1,32 @@
+//
+// 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.
+//
+
+#include "compiler/InitializeDll.h"
+
+#include "compiler/InitializeGlobals.h"
+#include "compiler/InitializeParseContext.h"
+#include "compiler/osinclude.h"
+
+bool InitProcess()
+{
+ if (!InitializePoolIndex()) {
+ assert(0 && "InitProcess(): Failed to initalize global pool");
+ return false;
+ }
+
+ if (!InitializeParseContextIndex()) {
+ assert(0 && "InitProcess(): Failed to initalize parse context");
+ return false;
+ }
+
+ return true;
+}
+
+void DetachProcess()
+{
+ FreeParseContextIndex();
+ FreePoolIndex();
+}
diff --git a/src/compiler/InitializeDll.h b/src/compiler/InitializeDll.h
new file mode 100644
index 00000000..43070cc3
--- /dev/null
+++ b/src/compiler/InitializeDll.h
@@ -0,0 +1,13 @@
+//
+// 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.
+//
+#ifndef __INITIALIZEDLL_H
+#define __INITIALIZEDLL_H
+
+bool InitProcess();
+void DetachProcess();
+
+#endif // __INITIALIZEDLL_H
+
diff --git a/src/compiler/InitializeGlobals.h b/src/compiler/InitializeGlobals.h
new file mode 100644
index 00000000..07159414
--- /dev/null
+++ b/src/compiler/InitializeGlobals.h
@@ -0,0 +1,13 @@
+//
+// 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.
+//
+
+#ifndef __INITIALIZE_GLOBALS_INCLUDED_
+#define __INITIALIZE_GLOBALS_INCLUDED_
+
+bool InitializePoolIndex();
+void FreePoolIndex();
+
+#endif // __INITIALIZE_GLOBALS_INCLUDED_
diff --git a/src/compiler/InitializeParseContext.cpp b/src/compiler/InitializeParseContext.cpp
new file mode 100644
index 00000000..dfab0273
--- /dev/null
+++ b/src/compiler/InitializeParseContext.cpp
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/InitializeParseContext.h"
+
+#include "compiler/osinclude.h"
+
+OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
+
+bool InitializeParseContextIndex()
+{
+ assert(GlobalParseContextIndex == OS_INVALID_TLS_INDEX);
+
+ GlobalParseContextIndex = OS_AllocTLSIndex();
+ return GlobalParseContextIndex != OS_INVALID_TLS_INDEX;
+}
+
+void FreeParseContextIndex()
+{
+ assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX);
+
+ OS_FreeTLSIndex(GlobalParseContextIndex);
+ GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
+}
+
+void SetGlobalParseContext(TParseContext* context)
+{
+ assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX);
+ OS_SetTLSValue(GlobalParseContextIndex, context);
+}
+
+TParseContext* GetGlobalParseContext()
+{
+ assert(GlobalParseContextIndex != OS_INVALID_TLS_INDEX);
+ return static_cast<TParseContext*>(OS_GetTLSValue(GlobalParseContextIndex));
+}
+
diff --git a/src/compiler/InitializeParseContext.h b/src/compiler/InitializeParseContext.h
new file mode 100644
index 00000000..bffbab87
--- /dev/null
+++ b/src/compiler/InitializeParseContext.h
@@ -0,0 +1,17 @@
+//
+// 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.
+//
+
+#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+
+bool InitializeParseContextIndex();
+void FreeParseContextIndex();
+
+struct TParseContext;
+extern void SetGlobalParseContext(TParseContext* context);
+extern TParseContext* GetGlobalParseContext();
+
+#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_
diff --git a/src/compiler/IntermTraverse.cpp b/src/compiler/IntermTraverse.cpp
new file mode 100644
index 00000000..a13877f1
--- /dev/null
+++ b/src/compiler/IntermTraverse.cpp
@@ -0,0 +1,293 @@
+//
+// 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.
+//
+
+#include "compiler/intermediate.h"
+
+//
+// Traverse the intermediate representation tree, and
+// call a node type specific function for each node.
+// Done recursively through the member function Traverse().
+// Node types can be skipped if their function to call is 0,
+// but their subtree will still be traversed.
+// Nodes with children can have their whole subtree skipped
+// if preVisit is turned on and the type specific function
+// returns false.
+//
+// preVisit, postVisit, and rightToLeft control what order
+// nodes are visited in.
+//
+
+//
+// Traversal functions for terminals are straighforward....
+//
+void TIntermSymbol::traverse(TIntermTraverser* it)
+{
+ it->visitSymbol(this);
+}
+
+void TIntermConstantUnion::traverse(TIntermTraverser* it)
+{
+ it->visitConstantUnion(this);
+}
+
+//
+// Traverse a binary node.
+//
+void TIntermBinary::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ //
+ // visit the node before children if pre-visiting.
+ //
+ if(it->preVisit)
+ {
+ visit = it->visitBinary(PreVisit, this);
+ }
+
+ //
+ // Visit the children, in the right order.
+ //
+ if(visit)
+ {
+ it->incrementDepth();
+
+ if(it->rightToLeft)
+ {
+ if(right)
+ {
+ right->traverse(it);
+ }
+
+ if(it->inVisit)
+ {
+ visit = it->visitBinary(InVisit, this);
+ }
+
+ if(visit && left)
+ {
+ left->traverse(it);
+ }
+ }
+ else
+ {
+ if(left)
+ {
+ left->traverse(it);
+ }
+
+ if(it->inVisit)
+ {
+ visit = it->visitBinary(InVisit, this);
+ }
+
+ if(visit && right)
+ {
+ right->traverse(it);
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ //
+ // Visit the node after the children, if requested and the traversal
+ // hasn't been cancelled yet.
+ //
+ if(visit && it->postVisit)
+ {
+ it->visitBinary(PostVisit, this);
+ }
+}
+
+//
+// Traverse a unary node. Same comments in binary node apply here.
+//
+void TIntermUnary::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitUnary(PreVisit, this);
+
+ if (visit) {
+ it->incrementDepth();
+ operand->traverse(it);
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitUnary(PostVisit, this);
+}
+
+//
+// Traverse an aggregate node. Same comments in binary node apply here.
+//
+void TIntermAggregate::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if(it->preVisit)
+ {
+ visit = it->visitAggregate(PreVisit, this);
+ }
+
+ if(visit)
+ {
+ it->incrementDepth();
+
+ if(it->rightToLeft)
+ {
+ for(TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++)
+ {
+ (*sit)->traverse(it);
+
+ if(visit && it->inVisit)
+ {
+ if(*sit != sequence.front())
+ {
+ visit = it->visitAggregate(InVisit, this);
+ }
+ }
+ }
+ }
+ else
+ {
+ for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ (*sit)->traverse(it);
+
+ if(visit && it->inVisit)
+ {
+ if(*sit != sequence.back())
+ {
+ visit = it->visitAggregate(InVisit, this);
+ }
+ }
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ if(visit && it->postVisit)
+ {
+ it->visitAggregate(PostVisit, this);
+ }
+}
+
+//
+// Traverse a selection node. Same comments in binary node apply here.
+//
+void TIntermSelection::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitSelection(PreVisit, this);
+
+ if (visit) {
+ it->incrementDepth();
+ if (it->rightToLeft) {
+ if (falseBlock)
+ falseBlock->traverse(it);
+ if (trueBlock)
+ trueBlock->traverse(it);
+ condition->traverse(it);
+ } else {
+ condition->traverse(it);
+ if (trueBlock)
+ trueBlock->traverse(it);
+ if (falseBlock)
+ falseBlock->traverse(it);
+ }
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitSelection(PostVisit, this);
+}
+
+//
+// Traverse a loop node. Same comments in binary node apply here.
+//
+void TIntermLoop::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if(it->preVisit)
+ {
+ visit = it->visitLoop(PreVisit, this);
+ }
+
+ if(visit)
+ {
+ it->incrementDepth();
+
+ if(it->rightToLeft)
+ {
+ if(expr)
+ {
+ expr->traverse(it);
+ }
+
+ if(body)
+ {
+ body->traverse(it);
+ }
+
+ if(cond)
+ {
+ cond->traverse(it);
+ }
+ }
+ else
+ {
+ if(cond)
+ {
+ cond->traverse(it);
+ }
+
+ if(body)
+ {
+ body->traverse(it);
+ }
+
+ if(expr)
+ {
+ expr->traverse(it);
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ if(visit && it->postVisit)
+ {
+ it->visitLoop(PostVisit, this);
+ }
+}
+
+//
+// Traverse a branch node. Same comments in binary node apply here.
+//
+void TIntermBranch::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitBranch(PreVisit, this);
+
+ if (visit && expression) {
+ it->incrementDepth();
+ expression->traverse(it);
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitBranch(PostVisit, this);
+}
+
diff --git a/src/compiler/Intermediate.cpp b/src/compiler/Intermediate.cpp
new file mode 100644
index 00000000..3b662218
--- /dev/null
+++ b/src/compiler/Intermediate.cpp
@@ -0,0 +1,1442 @@
+//
+// 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.
+//
+
+//
+// Build the intermediate representation.
+//
+
+#include <float.h>
+#include <limits.h>
+#include <algorithm>
+
+#include "compiler/HashNames.h"
+#include "compiler/localintermediate.h"
+#include "compiler/QualifierAlive.h"
+#include "compiler/RemoveTree.h"
+
+bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
+
+static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
+ return left > right ? left : right;
+}
+
+const char* getOperatorString(TOperator op) {
+ switch (op) {
+ case EOpInitialize: return "=";
+ case EOpAssign: return "=";
+ case EOpAddAssign: return "+=";
+ case EOpSubAssign: return "-=";
+ case EOpDivAssign: return "/=";
+
+ // Fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign: return "*=";
+
+ // Fall-through.
+ case EOpIndexDirect:
+ case EOpIndexIndirect: return "[]";
+
+ case EOpIndexDirectStruct: return ".";
+ case EOpVectorSwizzle: return ".";
+ case EOpAdd: return "+";
+ case EOpSub: return "-";
+ case EOpMul: return "*";
+ case EOpDiv: return "/";
+ case EOpMod: UNIMPLEMENTED(); break;
+ case EOpEqual: return "==";
+ case EOpNotEqual: return "!=";
+ case EOpLessThan: return "<";
+ case EOpGreaterThan: return ">";
+ case EOpLessThanEqual: return "<=";
+ case EOpGreaterThanEqual: return ">=";
+
+ // Fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix: return "*";
+
+ case EOpLogicalOr: return "||";
+ case EOpLogicalXor: return "^^";
+ case EOpLogicalAnd: return "&&";
+ case EOpNegative: return "-";
+ case EOpVectorLogicalNot: return "not";
+ case EOpLogicalNot: return "!";
+ case EOpPostIncrement: return "++";
+ case EOpPostDecrement: return "--";
+ case EOpPreIncrement: return "++";
+ case EOpPreDecrement: return "--";
+
+ // Fall-through.
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool: return "bool";
+
+ // Fall-through.
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat: return "float";
+
+ // Fall-through.
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt: return "int";
+
+ case EOpRadians: return "radians";
+ case EOpDegrees: return "degrees";
+ case EOpSin: return "sin";
+ case EOpCos: return "cos";
+ case EOpTan: return "tan";
+ case EOpAsin: return "asin";
+ case EOpAcos: return "acos";
+ case EOpAtan: return "atan";
+ case EOpExp: return "exp";
+ case EOpLog: return "log";
+ case EOpExp2: return "exp2";
+ case EOpLog2: return "log2";
+ case EOpSqrt: return "sqrt";
+ case EOpInverseSqrt: return "inversesqrt";
+ case EOpAbs: return "abs";
+ case EOpSign: return "sign";
+ case EOpFloor: return "floor";
+ case EOpCeil: return "ceil";
+ case EOpFract: return "fract";
+ case EOpLength: return "length";
+ case EOpNormalize: return "normalize";
+ case EOpDFdx: return "dFdx";
+ case EOpDFdy: return "dFdy";
+ case EOpFwidth: return "fwidth";
+ case EOpAny: return "any";
+ case EOpAll: return "all";
+
+ default: break;
+ }
+ return "";
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// First set of functions are to help build the intermediate representation.
+// These functions are not member functions of the nodes.
+// They are called from parser productions.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+//
+// Add a terminal node for an identifier in an expression.
+//
+// Returns the added node.
+//
+TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, const TSourceLoc& line)
+{
+ TIntermSymbol* node = new TIntermSymbol(id, name, type);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Connect two nodes with a new parent that does a binary operation on the nodes.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line, TSymbolTable& symbolTable)
+{
+ switch (op) {
+ case EOpEqual:
+ case EOpNotEqual:
+ if (left->isArray())
+ return 0;
+ break;
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
+ return 0;
+ }
+ break;
+ case EOpLogicalOr:
+ case EOpLogicalXor:
+ case EOpLogicalAnd:
+ if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
+ return 0;
+ }
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpMul:
+ if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
+ return 0;
+ default: break;
+ }
+
+ //
+ // First try converting the children to compatible types.
+ //
+ if (left->getType().getStruct() && right->getType().getStruct()) {
+ if (left->getType() != right->getType())
+ return 0;
+ } else {
+ TIntermTyped* child = addConversion(op, left->getType(), right);
+ if (child)
+ right = child;
+ else {
+ child = addConversion(op, right->getType(), left);
+ if (child)
+ left = child;
+ else
+ return 0;
+ }
+ }
+
+ //
+ // Need a new node holding things together then. Make
+ // one and promote it to the right type.
+ //
+ TIntermBinary* node = new TIntermBinary(op);
+ node->setLine(line);
+
+ node->setLeft(left);
+ node->setRight(right);
+ if (!node->promote(infoSink))
+ return 0;
+
+ //
+ // See if we can fold constants.
+ //
+ TIntermTyped* typedReturnNode = 0;
+ TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
+ TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
+ if (leftTempConstant && rightTempConstant) {
+ typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
+
+ if (typedReturnNode)
+ return typedReturnNode;
+ }
+
+ return node;
+}
+
+//
+// Connect two nodes through an assignment.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
+{
+ //
+ // Like adding binary math, except the conversion can only go
+ // from right to left.
+ //
+ TIntermBinary* node = new TIntermBinary(op);
+ node->setLine(line);
+
+ TIntermTyped* child = addConversion(op, left->getType(), right);
+ if (child == 0)
+ return 0;
+
+ node->setLeft(left);
+ node->setRight(child);
+ if (! node->promote(infoSink))
+ return 0;
+
+ return node;
+}
+
+//
+// Connect two nodes through an index operator, where the left node is the base
+// of an array or struct, and the right node is a direct or indirect offset.
+//
+// Returns the added node.
+// The caller should set the type of the returned node.
+//
+TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc& line)
+{
+ TIntermBinary* node = new TIntermBinary(op);
+ node->setLine(line);
+ node->setLeft(base);
+ node->setRight(index);
+
+ // caller should set the type
+
+ return node;
+}
+
+//
+// Add one node as the parent of another that it operates on.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, const TSourceLoc& line, TSymbolTable& symbolTable)
+{
+ TIntermUnary* node;
+ TIntermTyped* child = childNode->getAsTyped();
+
+ if (child == 0) {
+ infoSink.info.message(EPrefixInternalError, line, "Bad type in AddUnaryMath");
+ return 0;
+ }
+
+ switch (op) {
+ case EOpLogicalNot:
+ if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
+ return 0;
+ }
+ break;
+
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ case EOpNegative:
+ if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
+ return 0;
+ default: break;
+ }
+
+ //
+ // Do we need to promote the operand?
+ //
+ // Note: Implicit promotions were removed from the language.
+ //
+ TBasicType newType = EbtVoid;
+ switch (op) {
+ case EOpConstructInt: newType = EbtInt; break;
+ case EOpConstructBool: newType = EbtBool; break;
+ case EOpConstructFloat: newType = EbtFloat; break;
+ default: break;
+ }
+
+ if (newType != EbtVoid) {
+ child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
+ child->getNominalSize(),
+ child->isMatrix(),
+ child->isArray()),
+ child);
+ if (child == 0)
+ return 0;
+ }
+
+ //
+ // For constructors, we are now done, it's all in the conversion.
+ //
+ switch (op) {
+ case EOpConstructInt:
+ case EOpConstructBool:
+ case EOpConstructFloat:
+ return child;
+ default: break;
+ }
+
+ TIntermConstantUnion *childTempConstant = 0;
+ if (child->getAsConstantUnion())
+ childTempConstant = child->getAsConstantUnion();
+
+ //
+ // Make a new node for the operator.
+ //
+ node = new TIntermUnary(op);
+ node->setLine(line);
+ node->setOperand(child);
+
+ if (! node->promote(infoSink))
+ return 0;
+
+ if (childTempConstant) {
+ TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
+
+ if (newChild)
+ return newChild;
+ }
+
+ return node;
+}
+
+//
+// This is the safe way to change the operator on an aggregate, as it
+// does lots of error checking and fixing. Especially for establishing
+// a function call's operation on it's set of parameters. Sequences
+// of instructions are also aggregates, but they just direnctly set
+// their operator to EOpSequence.
+//
+// Returns an aggregate node, which could be the one passed in if
+// it was already an aggregate but no operator was set.
+//
+TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, const TSourceLoc& line)
+{
+ TIntermAggregate* aggNode;
+
+ //
+ // Make sure we have an aggregate. If not turn it into one.
+ //
+ if (node) {
+ aggNode = node->getAsAggregate();
+ if (aggNode == 0 || aggNode->getOp() != EOpNull) {
+ //
+ // Make an aggregate containing this node.
+ //
+ aggNode = new TIntermAggregate();
+ aggNode->getSequence().push_back(node);
+ }
+ } else
+ aggNode = new TIntermAggregate();
+
+ //
+ // Set the operator.
+ //
+ aggNode->setOp(op);
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Convert one type to another.
+//
+// Returns the node representing the conversion, which could be the same
+// node passed in if no conversion was needed.
+//
+// Return 0 if a conversion can't be done.
+//
+TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
+{
+ //
+ // Does the base type allow operation?
+ //
+ switch (node->getBasicType()) {
+ case EbtVoid:
+ case EbtSampler2D:
+ case EbtSamplerCube:
+ return 0;
+ default: break;
+ }
+
+ //
+ // Otherwise, if types are identical, no problem
+ //
+ if (type == node->getType())
+ return node;
+
+ //
+ // If one's a structure, then no conversions.
+ //
+ if (type.getStruct() || node->getType().getStruct())
+ return 0;
+
+ //
+ // If one's an array, then no conversions.
+ //
+ if (type.isArray() || node->getType().isArray())
+ return 0;
+
+ TBasicType promoteTo;
+
+ switch (op) {
+ //
+ // Explicit conversions
+ //
+ case EOpConstructBool:
+ promoteTo = EbtBool;
+ break;
+ case EOpConstructFloat:
+ promoteTo = EbtFloat;
+ break;
+ case EOpConstructInt:
+ promoteTo = EbtInt;
+ break;
+ default:
+ //
+ // implicit conversions were removed from the language.
+ //
+ if (type.getBasicType() != node->getType().getBasicType())
+ return 0;
+ //
+ // Size and structure could still differ, but that's
+ // handled by operator promotion.
+ //
+ return node;
+ }
+
+ if (node->getAsConstantUnion()) {
+
+ return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
+ } else {
+
+ //
+ // Add a new newNode for the conversion.
+ //
+ TIntermUnary* newNode = 0;
+
+ TOperator newOp = EOpNull;
+ switch (promoteTo) {
+ case EbtFloat:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToFloat; break;
+ case EbtBool: newOp = EOpConvBoolToFloat; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
+ return 0;
+ }
+ break;
+ case EbtBool:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToBool; break;
+ case EbtFloat: newOp = EOpConvFloatToBool; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
+ return 0;
+ }
+ break;
+ case EbtInt:
+ switch (node->getBasicType()) {
+ case EbtBool: newOp = EOpConvBoolToInt; break;
+ case EbtFloat: newOp = EOpConvFloatToInt; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion node");
+ return 0;
+ }
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Bad promotion type");
+ return 0;
+ }
+
+ TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
+ newNode = new TIntermUnary(newOp, type);
+ newNode->setLine(node->getLine());
+ newNode->setOperand(node);
+
+ return newNode;
+ }
+}
+
+//
+// Safe way to combine two nodes into an aggregate. Works with null pointers,
+// a node that's not a aggregate yet, etc.
+//
+// Returns the resulting aggregate, unless 0 was passed in for
+// both existing nodes.
+//
+TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& line)
+{
+ if (left == 0 && right == 0)
+ return 0;
+
+ TIntermAggregate* aggNode = 0;
+ if (left)
+ aggNode = left->getAsAggregate();
+ if (!aggNode || aggNode->getOp() != EOpNull) {
+ aggNode = new TIntermAggregate;
+ if (left)
+ aggNode->getSequence().push_back(left);
+ }
+
+ if (right)
+ aggNode->getSequence().push_back(right);
+
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Turn an existing node into an aggregate.
+//
+// Returns an aggregate, unless 0 was passed in for the existing node.
+//
+TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, const TSourceLoc& line)
+{
+ if (node == 0)
+ return 0;
+
+ TIntermAggregate* aggNode = new TIntermAggregate;
+ aggNode->getSequence().push_back(node);
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// For "if" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are in the
+// nodePair.
+//
+// Returns the selection node created.
+//
+TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& line)
+{
+ //
+ // For compile time constant selections, prune the code and
+ // test now.
+ //
+
+ if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
+ if (cond->getAsConstantUnion()->getBConst(0) == true)
+ return nodePair.node1 ? setAggregateOperator(nodePair.node1, EOpSequence, nodePair.node1->getLine()) : NULL;
+ else
+ return nodePair.node2 ? setAggregateOperator(nodePair.node2, EOpSequence, nodePair.node2->getLine()) : NULL;
+ }
+
+ TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
+ node->setLine(line);
+
+ return node;
+}
+
+
+TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc& line)
+{
+ if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
+ return right;
+ } else {
+ TIntermTyped *commaAggregate = growAggregate(left, right, line);
+ commaAggregate->getAsAggregate()->setOp(EOpComma);
+ commaAggregate->setType(right->getType());
+ commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
+ return commaAggregate;
+ }
+}
+
+//
+// For "?:" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are specified
+// as separate parameters.
+//
+// Returns the selection node created, or 0 if one could not be.
+//
+TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& line)
+{
+ //
+ // Get compatible types.
+ //
+ TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
+ if (child)
+ falseBlock = child;
+ else {
+ child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
+ if (child)
+ trueBlock = child;
+ else
+ return 0;
+ }
+
+ //
+ // See if all the operands are constant, then fold it otherwise not.
+ //
+
+ if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
+ if (cond->getAsConstantUnion()->getBConst(0))
+ return trueBlock;
+ else
+ return falseBlock;
+ }
+
+ //
+ // Make a selection node.
+ //
+ TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
+ node->getTypePointer()->setQualifier(EvqTemporary);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Constant terminal nodes. Has a union that contains bool, float or int constants
+//
+// Returns the constant union node created.
+//
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, const TSourceLoc& line)
+{
+ TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, const TSourceLoc& line)
+{
+
+ TIntermAggregate* node = new TIntermAggregate(EOpSequence);
+
+ node->setLine(line);
+ TIntermConstantUnion* constIntNode;
+ TIntermSequence &sequenceVector = node->getSequence();
+ ConstantUnion* unionArray;
+
+ for (int i = 0; i < fields.num; i++) {
+ unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.offsets[i]);
+ constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
+ sequenceVector.push_back(constIntNode);
+ }
+
+ return node;
+}
+
+//
+// Create loop nodes.
+//
+TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, const TSourceLoc& line)
+{
+ TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Add branches.
+//
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, const TSourceLoc& line)
+{
+ return addBranch(branchOp, 0, line);
+}
+
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, const TSourceLoc& line)
+{
+ TIntermBranch* node = new TIntermBranch(branchOp, expression);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// This is to be executed once the final root is put on top by the parsing
+// process.
+//
+bool TIntermediate::postProcess(TIntermNode* root)
+{
+ if (root == 0)
+ return true;
+
+ //
+ // First, finish off the top level sequence, if any
+ //
+ TIntermAggregate* aggRoot = root->getAsAggregate();
+ if (aggRoot && aggRoot->getOp() == EOpNull)
+ aggRoot->setOp(EOpSequence);
+
+ return true;
+}
+
+//
+// This deletes the tree.
+//
+void TIntermediate::remove(TIntermNode* root)
+{
+ if (root)
+ RemoveAllTreeNodes(root);
+}
+
+////////////////////////////////////////////////////////////////
+//
+// Member functions of the nodes used for building the tree.
+//
+////////////////////////////////////////////////////////////////
+
+//
+// Say whether or not an operation node changes the value of a variable.
+//
+// Returns true if state is modified.
+//
+bool TIntermOperator::modifiesState() const
+{
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ case EOpAssign:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ case EOpDivAssign:
+ return true;
+ default:
+ return false;
+ }
+}
+
+//
+// returns true if the operator is for one of the constructors
+//
+bool TIntermOperator::isConstructor() const
+{
+ switch (op) {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ case EOpConstructFloat:
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ case EOpConstructStruct:
+ return true;
+ default:
+ return false;
+ }
+}
+//
+// Make sure the type of a unary operator is appropriate for its
+// combination of operation and operand type.
+//
+// Returns false in nothing makes sense.
+//
+bool TIntermUnary::promote(TInfoSink&)
+{
+ switch (op) {
+ case EOpLogicalNot:
+ if (operand->getBasicType() != EbtBool)
+ return false;
+ break;
+ case EOpNegative:
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ if (operand->getBasicType() == EbtBool)
+ return false;
+ break;
+
+ // operators for built-ins are already type checked against their prototype
+ case EOpAny:
+ case EOpAll:
+ case EOpVectorLogicalNot:
+ return true;
+
+ default:
+ if (operand->getBasicType() != EbtFloat)
+ return false;
+ }
+
+ setType(operand->getType());
+ type.setQualifier(EvqTemporary);
+
+ return true;
+}
+
+//
+// Establishes the type of the resultant operation, as well as
+// makes the operator the correct one for the operands.
+//
+// Returns false if operator can't work on operands.
+//
+bool TIntermBinary::promote(TInfoSink& infoSink)
+{
+ // This function only handles scalars, vectors, and matrices.
+ if (left->isArray() || right->isArray()) {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operation for arrays");
+ return false;
+ }
+
+ // GLSL ES 2.0 does not support implicit type casting.
+ // So the basic type should always match.
+ if (left->getBasicType() != right->getBasicType())
+ return false;
+
+ //
+ // Base assumption: just make the type the same as the left
+ // operand. Then only deviations from this need be coded.
+ //
+ setType(left->getType());
+
+ // The result gets promoted to the highest precision.
+ TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
+ getTypePointer()->setPrecision(higherPrecision);
+
+ // Binary operations results in temporary variables unless both
+ // operands are const.
+ if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
+ getTypePointer()->setQualifier(EvqTemporary);
+ }
+
+ int size = std::max(left->getNominalSize(), right->getNominalSize());
+
+ //
+ // All scalars. Code after this test assumes this case is removed!
+ //
+ if (size == 1) {
+ switch (op) {
+ //
+ // Promote to conditional
+ //
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ //
+ // And and Or operate on conditionals
+ //
+ case EOpLogicalAnd:
+ case EOpLogicalOr:
+ // Both operands must be of type bool.
+ if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
+ return false;
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ default:
+ break;
+ }
+ return true;
+ }
+
+ // If we reach here, at least one of the operands is vector or matrix.
+ // The other operand could be a scalar, vector, or matrix.
+ // Are the sizes compatible?
+ //
+ if (left->getNominalSize() != right->getNominalSize()) {
+ // If the nominal size of operands do not match:
+ // One of them must be scalar.
+ if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
+ return false;
+ // Operator cannot be of type pure assignment.
+ if (op == EOpAssign || op == EOpInitialize)
+ return false;
+ }
+
+ //
+ // Can these two operands be combined?
+ //
+ TBasicType basicType = left->getBasicType();
+ switch (op) {
+ case EOpMul:
+ if (!left->isMatrix() && right->isMatrix()) {
+ if (left->isVector())
+ op = EOpVectorTimesMatrix;
+ else {
+ op = EOpMatrixTimesScalar;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
+ }
+ } else if (left->isMatrix() && !right->isMatrix()) {
+ if (right->isVector()) {
+ op = EOpMatrixTimesVector;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ } else {
+ op = EOpMatrixTimesScalar;
+ }
+ } else if (left->isMatrix() && right->isMatrix()) {
+ op = EOpMatrixTimesMatrix;
+ } else if (!left->isMatrix() && !right->isMatrix()) {
+ if (left->isVector() && right->isVector()) {
+ // leave as component product
+ } else if (left->isVector() || right->isVector()) {
+ op = EOpVectorTimesScalar;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ }
+ } else {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
+ return false;
+ }
+ break;
+ case EOpMulAssign:
+ if (!left->isMatrix() && right->isMatrix()) {
+ if (left->isVector())
+ op = EOpVectorTimesMatrixAssign;
+ else {
+ return false;
+ }
+ } else if (left->isMatrix() && !right->isMatrix()) {
+ if (right->isVector()) {
+ return false;
+ } else {
+ op = EOpMatrixTimesScalarAssign;
+ }
+ } else if (left->isMatrix() && right->isMatrix()) {
+ op = EOpMatrixTimesMatrixAssign;
+ } else if (!left->isMatrix() && !right->isMatrix()) {
+ if (left->isVector() && right->isVector()) {
+ // leave as component product
+ } else if (left->isVector() || right->isVector()) {
+ if (! left->isVector())
+ return false;
+ op = EOpVectorTimesScalarAssign;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ }
+ } else {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Missing elses");
+ return false;
+ }
+ break;
+
+ case EOpAssign:
+ case EOpInitialize:
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpDivAssign:
+ if ((left->isMatrix() && right->isVector()) ||
+ (left->isVector() && right->isMatrix()))
+ return false;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
+ break;
+
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if ((left->isMatrix() && right->isVector()) ||
+ (left->isVector() && right->isMatrix()))
+ return false;
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
+{
+ const TFieldList& fields = leftNodeType.getStruct()->fields();
+
+ size_t structSize = fields.size();
+ size_t index = 0;
+
+ for (size_t j = 0; j < structSize; j++) {
+ size_t size = fields[j]->type()->getObjectSize();
+ for (size_t i = 0; i < size; i++) {
+ if (fields[j]->type()->getBasicType() == EbtStruct) {
+ if (!CompareStructure(*(fields[j]->type()), &rightUnionArray[index], &leftUnionArray[index]))
+ return false;
+ } else {
+ if (leftUnionArray[index] != rightUnionArray[index])
+ return false;
+ index++;
+ }
+ }
+ }
+ return true;
+}
+
+bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
+{
+ if (leftNodeType.isArray()) {
+ TType typeWithoutArrayness = leftNodeType;
+ typeWithoutArrayness.clearArrayness();
+
+ size_t arraySize = leftNodeType.getArraySize();
+
+ for (size_t i = 0; i < arraySize; ++i) {
+ size_t offset = typeWithoutArrayness.getObjectSize() * i;
+ if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
+ return false;
+ }
+ } else
+ return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
+
+ return true;
+}
+
+//
+// The fold functions see if an operation on a constant can be done in place,
+// without generating run-time code.
+//
+// Returns the node to keep using, which may or may not be the node passed in.
+//
+
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
+{
+ ConstantUnion *unionArray = getUnionArrayPointer();
+ size_t objectSize = getType().getObjectSize();
+
+ if (constantNode) { // binary operations
+ TIntermConstantUnion *node = constantNode->getAsConstantUnion();
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ TType returnType = getType();
+
+ // for a case like float f = 1.2 + vec4(2,3,4,5);
+ if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
+ rightUnionArray = new ConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; ++i)
+ rightUnionArray[i] = *node->getUnionArrayPointer();
+ returnType = getType();
+ } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
+ // for a case like float f = vec4(2,3,4,5) + 1.2;
+ unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
+ for (size_t i = 0; i < constantNode->getType().getObjectSize(); ++i)
+ unionArray[i] = *getUnionArrayPointer();
+ returnType = node->getType();
+ objectSize = constantNode->getType().getObjectSize();
+ }
+
+ ConstantUnion* tempConstArray = 0;
+ TIntermConstantUnion *tempNode;
+
+ bool boolNodeFlag = false;
+ switch(op) {
+ case EOpAdd:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (size_t i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] + rightUnionArray[i];
+ }
+ break;
+ case EOpSub:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (size_t i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] - rightUnionArray[i];
+ }
+ break;
+
+ case EOpMul:
+ case EOpVectorTimesScalar:
+ case EOpMatrixTimesScalar:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (size_t i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] * rightUnionArray[i];
+ }
+ break;
+ case EOpMatrixTimesMatrix:
+ if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix multiply");
+ return 0;
+ }
+ {// support MSVC++6.0
+ int size = getNominalSize();
+ tempConstArray = new ConstantUnion[size*size];
+ for (int row = 0; row < size; row++) {
+ for (int column = 0; column < size; column++) {
+ tempConstArray[size * column + row].setFConst(0.0f);
+ for (int i = 0; i < size; i++) {
+ tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
+ }
+ }
+ }
+ }
+ break;
+ case EOpDiv:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (size_t i = 0; i < objectSize; i++) {
+ switch (getType().getBasicType()) {
+ case EbtFloat:
+ if (rightUnionArray[i] == 0.0f) {
+ infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
+ tempConstArray[i].setFConst(unionArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
+ } else
+ tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
+ break;
+
+ case EbtInt:
+ if (rightUnionArray[i] == 0) {
+ infoSink.info.message(EPrefixWarning, getLine(), "Divide by zero error during constant folding");
+ tempConstArray[i].setIConst(INT_MAX);
+ } else
+ tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, getLine(), "Constant folding cannot be done for \"/\"");
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case EOpMatrixTimesVector:
+ if (node->getBasicType() != EbtFloat) {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for matrix times vector");
+ return 0;
+ }
+ tempConstArray = new ConstantUnion[getNominalSize()];
+
+ {// support MSVC++6.0
+ for (int size = getNominalSize(), i = 0; i < size; i++) {
+ tempConstArray[i].setFConst(0.0f);
+ for (int j = 0; j < size; j++) {
+ tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
+ }
+ }
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ case EOpVectorTimesMatrix:
+ if (getType().getBasicType() != EbtFloat) {
+ infoSink.info.message(EPrefixInternalError, getLine(), "Constant Folding cannot be done for vector times matrix");
+ return 0;
+ }
+
+ tempConstArray = new ConstantUnion[getNominalSize()];
+ {// support MSVC++6.0
+ for (int size = getNominalSize(), i = 0; i < size; i++) {
+ tempConstArray[i].setFConst(0.0f);
+ for (int j = 0; j < size; j++) {
+ tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
+ }
+ }
+ }
+ break;
+
+ case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (size_t i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] && rightUnionArray[i];
+ }
+ break;
+
+ case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (size_t i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] || rightUnionArray[i];
+ }
+ break;
+
+ case EOpLogicalXor:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (size_t i = 0; i < objectSize; i++)
+ switch (getType().getBasicType()) {
+ case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
+ default: assert(false && "Default missing");
+ }
+ }
+ break;
+
+ case EOpLessThan:
+ assert(objectSize == 1);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(*unionArray < *rightUnionArray);
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ case EOpGreaterThan:
+ assert(objectSize == 1);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(*unionArray > *rightUnionArray);
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ case EOpLessThanEqual:
+ {
+ assert(objectSize == 1);
+ ConstantUnion constant;
+ constant.setBConst(*unionArray > *rightUnionArray);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(!constant.getBConst());
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ }
+ case EOpGreaterThanEqual:
+ {
+ assert(objectSize == 1);
+ ConstantUnion constant;
+ constant.setBConst(*unionArray < *rightUnionArray);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(!constant.getBConst());
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ }
+
+ case EOpEqual:
+ if (getType().getBasicType() == EbtStruct) {
+ if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
+ boolNodeFlag = true;
+ } else {
+ for (size_t i = 0; i < objectSize; i++) {
+ if (unionArray[i] != rightUnionArray[i]) {
+ boolNodeFlag = true;
+ break; // break out of for loop
+ }
+ }
+ }
+
+ tempConstArray = new ConstantUnion[1];
+ if (!boolNodeFlag) {
+ tempConstArray->setBConst(true);
+ }
+ else {
+ tempConstArray->setBConst(false);
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ case EOpNotEqual:
+ if (getType().getBasicType() == EbtStruct) {
+ if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
+ boolNodeFlag = true;
+ } else {
+ for (size_t i = 0; i < objectSize; i++) {
+ if (unionArray[i] == rightUnionArray[i]) {
+ boolNodeFlag = true;
+ break; // break out of for loop
+ }
+ }
+ }
+
+ tempConstArray = new ConstantUnion[1];
+ if (!boolNodeFlag) {
+ tempConstArray->setBConst(true);
+ }
+ else {
+ tempConstArray->setBConst(false);
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ default:
+ infoSink.info.message(EPrefixInternalError, getLine(), "Invalid operator for constant folding");
+ return 0;
+ }
+ tempNode = new TIntermConstantUnion(tempConstArray, returnType);
+ tempNode->setLine(getLine());
+
+ return tempNode;
+ } else {
+ //
+ // Do unary operations
+ //
+ TIntermConstantUnion *newNode = 0;
+ ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
+ for (size_t i = 0; i < objectSize; i++) {
+ switch(op) {
+ case EOpNegative:
+ switch (getType().getBasicType()) {
+ case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
+ case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
+ default:
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return 0;
+ }
+ break;
+ case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
+ switch (getType().getBasicType()) {
+ case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
+ default:
+ infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ }
+ newNode = new TIntermConstantUnion(tempConstArray, getType());
+ newNode->setLine(getLine());
+ return newNode;
+ }
+}
+
+TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
+{
+ size_t size = node->getType().getObjectSize();
+
+ ConstantUnion *leftUnionArray = new ConstantUnion[size];
+
+ for (size_t i = 0; i < size; i++) {
+
+ switch (promoteTo) {
+ case EbtFloat:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setFConst(static_cast<float>(node->getIConst(i)));
+ break;
+ case EbtBool:
+ leftUnionArray[i].setFConst(static_cast<float>(node->getBConst(i)));
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setFConst(static_cast<float>(node->getFConst(i)));
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
+ return 0;
+ }
+ break;
+ case EbtInt:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setIConst(static_cast<int>(node->getIConst(i)));
+ break;
+ case EbtBool:
+ leftUnionArray[i].setIConst(static_cast<int>(node->getBConst(i)));
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setIConst(static_cast<int>(node->getFConst(i)));
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
+ return 0;
+ }
+ break;
+ case EbtBool:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setBConst(node->getIConst(i) != 0);
+ break;
+ case EbtBool:
+ leftUnionArray[i].setBConst(node->getBConst(i));
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setBConst(node->getFConst(i) != 0.0f);
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Cannot promote");
+ return 0;
+ }
+
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Incorrect data type found");
+ return 0;
+ }
+
+ }
+
+ const TType& t = node->getType();
+
+ return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
+}
+
+// static
+TString TIntermTraverser::hash(const TString& name, ShHashFunction64 hashFunction)
+{
+ if (hashFunction == NULL || name.empty())
+ return name;
+ khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
+ TStringStream stream;
+ stream << HASHED_NAME_PREFIX << std::hex << number;
+ TString hashedName = stream.str();
+ return hashedName;
+}
diff --git a/src/compiler/MMap.h b/src/compiler/MMap.h
new file mode 100644
index 00000000..a3086715
--- /dev/null
+++ b/src/compiler/MMap.h
@@ -0,0 +1,56 @@
+//
+// 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.
+//
+
+#ifndef _MMAP_INCLUDED_
+#define _MMAP_INCLUDED_
+
+//
+// Encapsulate memory mapped files
+//
+
+class TMMap {
+public:
+ TMMap(const char* fileName) :
+ fSize(-1), // -1 is the error value returned by GetFileSize()
+ fp(NULL),
+ fBuff(0) // 0 is the error value returned by MapViewOfFile()
+ {
+ if ((fp = fopen(fileName, "r")) == NULL)
+ return;
+ char c = getc(fp);
+ fSize = 0;
+ while (c != EOF) {
+ fSize++;
+ c = getc(fp);
+ }
+ if (c == EOF)
+ fSize++;
+ rewind(fp);
+ fBuff = (char*)malloc(sizeof(char) * fSize);
+ int count = 0;
+ c = getc(fp);
+ while (c != EOF) {
+ fBuff[count++] = c;
+ c = getc(fp);
+ }
+ fBuff[count++] = c;
+ }
+
+ char* getData() { return fBuff; }
+ int getSize() { return fSize; }
+
+ ~TMMap() {
+ if (fp != NULL)
+ fclose(fp);
+ }
+
+private:
+ int fSize; // size of file to map in
+ FILE *fp;
+ char* fBuff; // the actual data;
+};
+
+#endif // _MMAP_INCLUDED_
diff --git a/src/compiler/MapLongVariableNames.cpp b/src/compiler/MapLongVariableNames.cpp
new file mode 100644
index 00000000..a41d20f4
--- /dev/null
+++ b/src/compiler/MapLongVariableNames.cpp
@@ -0,0 +1,122 @@
+//
+// 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.
+//
+
+#include "compiler/MapLongVariableNames.h"
+
+namespace {
+
+TString mapLongName(size_t id, const TString& name, bool isGlobal)
+{
+ ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE);
+ TStringStream stream;
+ stream << "webgl_";
+ if (isGlobal)
+ stream << "g";
+ stream << id;
+ if (name[0] != '_')
+ stream << "_";
+ stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size());
+ return stream.str();
+}
+
+LongNameMap* gLongNameMapInstance = NULL;
+
+} // anonymous namespace
+
+LongNameMap::LongNameMap()
+ : refCount(0)
+{
+}
+
+LongNameMap::~LongNameMap()
+{
+}
+
+// static
+LongNameMap* LongNameMap::GetInstance()
+{
+ if (gLongNameMapInstance == NULL)
+ gLongNameMapInstance = new LongNameMap;
+ gLongNameMapInstance->refCount++;
+ return gLongNameMapInstance;
+}
+
+void LongNameMap::Release()
+{
+ ASSERT(gLongNameMapInstance == this);
+ ASSERT(refCount > 0);
+ refCount--;
+ if (refCount == 0) {
+ delete gLongNameMapInstance;
+ gLongNameMapInstance = NULL;
+ }
+}
+
+const char* LongNameMap::Find(const char* originalName) const
+{
+ std::map<std::string, std::string>::const_iterator it = mLongNameMap.find(
+ originalName);
+ if (it != mLongNameMap.end())
+ return (*it).second.c_str();
+ return NULL;
+}
+
+void LongNameMap::Insert(const char* originalName, const char* mappedName)
+{
+ mLongNameMap.insert(std::map<std::string, std::string>::value_type(
+ originalName, mappedName));
+}
+
+size_t LongNameMap::Size() const
+{
+ return mLongNameMap.size();
+}
+
+MapLongVariableNames::MapLongVariableNames(LongNameMap* globalMap)
+{
+ ASSERT(globalMap);
+ mGlobalMap = globalMap;
+}
+
+void MapLongVariableNames::visitSymbol(TIntermSymbol* symbol)
+{
+ ASSERT(symbol != NULL);
+ if (symbol->getSymbol().size() > MAX_SHORTENED_IDENTIFIER_SIZE) {
+ switch (symbol->getQualifier()) {
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqInvariantVaryingIn:
+ case EvqInvariantVaryingOut:
+ case EvqUniform:
+ symbol->setSymbol(
+ mapGlobalLongName(symbol->getSymbol()));
+ break;
+ default:
+ symbol->setSymbol(
+ mapLongName(symbol->getId(), symbol->getSymbol(), false));
+ break;
+ };
+ }
+}
+
+bool MapLongVariableNames::visitLoop(Visit, TIntermLoop* node)
+{
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ return true;
+}
+
+TString MapLongVariableNames::mapGlobalLongName(const TString& name)
+{
+ ASSERT(mGlobalMap);
+ const char* mappedName = mGlobalMap->Find(name.c_str());
+ if (mappedName != NULL)
+ return mappedName;
+ size_t id = mGlobalMap->Size();
+ TString rt = mapLongName(id, name, true);
+ mGlobalMap->Insert(name.c_str(), rt.c_str());
+ return rt;
+}
diff --git a/src/compiler/MapLongVariableNames.h b/src/compiler/MapLongVariableNames.h
new file mode 100644
index 00000000..d6352acb
--- /dev/null
+++ b/src/compiler/MapLongVariableNames.h
@@ -0,0 +1,59 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_MAP_LONG_VARIABLE_NAMES_H_
+#define COMPILER_MAP_LONG_VARIABLE_NAMES_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/intermediate.h"
+#include "compiler/VariableInfo.h"
+
+// This size does not include '\0' in the end.
+#define MAX_SHORTENED_IDENTIFIER_SIZE 32
+
+// This is a ref-counted singleton. GetInstance() returns a pointer to the
+// singleton, and after use, call Release(). GetInstance() and Release() should
+// be paired.
+class LongNameMap {
+public:
+ static LongNameMap* GetInstance();
+ void Release();
+
+ // Return the mapped name if <originalName, mappedName> is in the map;
+ // otherwise, return NULL.
+ const char* Find(const char* originalName) const;
+
+ // Insert a pair into the map.
+ void Insert(const char* originalName, const char* mappedName);
+
+ // Return the number of entries in the map.
+ size_t Size() const;
+
+private:
+ LongNameMap();
+ ~LongNameMap();
+
+ size_t refCount;
+ std::map<std::string, std::string> mLongNameMap;
+};
+
+// Traverses intermediate tree to map attributes and uniforms names that are
+// longer than MAX_SHORTENED_IDENTIFIER_SIZE to MAX_SHORTENED_IDENTIFIER_SIZE.
+class MapLongVariableNames : public TIntermTraverser {
+public:
+ MapLongVariableNames(LongNameMap* globalMap);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+
+private:
+ TString mapGlobalLongName(const TString& name);
+
+ LongNameMap* mGlobalMap;
+};
+
+#endif // COMPILER_MAP_LONG_VARIABLE_NAMES_H_
diff --git a/src/compiler/OutputESSL.cpp b/src/compiler/OutputESSL.cpp
new file mode 100644
index 00000000..c2048f1c
--- /dev/null
+++ b/src/compiler/OutputESSL.cpp
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputESSL.h"
+
+TOutputESSL::TOutputESSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable)
+ : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable)
+{
+}
+
+bool TOutputESSL::writeVariablePrecision(TPrecision precision)
+{
+ if (precision == EbpUndefined)
+ return false;
+
+ TInfoSinkBase& out = objSink();
+ out << getPrecisionString(precision);
+ return true;
+}
diff --git a/src/compiler/OutputESSL.h b/src/compiler/OutputESSL.h
new file mode 100644
index 00000000..05db96e4
--- /dev/null
+++ b/src/compiler/OutputESSL.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTESSL_H_
+#define CROSSCOMPILERGLSL_OUTPUTESSL_H_
+
+#include "compiler/OutputGLSLBase.h"
+
+class TOutputESSL : public TOutputGLSLBase
+{
+public:
+ TOutputESSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable);
+
+protected:
+ virtual bool writeVariablePrecision(TPrecision precision);
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_
diff --git a/src/compiler/OutputGLSL.cpp b/src/compiler/OutputGLSL.cpp
new file mode 100644
index 00000000..10a451c0
--- /dev/null
+++ b/src/compiler/OutputGLSL.cpp
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputGLSL.h"
+
+TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable)
+ : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable)
+{
+}
+
+bool TOutputGLSL::writeVariablePrecision(TPrecision)
+{
+ return false;
+}
+
+void TOutputGLSL::visitSymbol(TIntermSymbol* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ if (node->getSymbol() == "gl_FragDepthEXT")
+ {
+ out << "gl_FragDepth";
+ }
+ else
+ {
+ TOutputGLSLBase::visitSymbol(node);
+ }
+}
diff --git a/src/compiler/OutputGLSL.h b/src/compiler/OutputGLSL.h
new file mode 100644
index 00000000..fa68ac81
--- /dev/null
+++ b/src/compiler/OutputGLSL.h
@@ -0,0 +1,26 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTGLSL_H_
+#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_
+
+#include "compiler/OutputGLSLBase.h"
+
+class TOutputGLSL : public TOutputGLSLBase
+{
+public:
+ TOutputGLSL(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable);
+
+protected:
+ virtual bool writeVariablePrecision(TPrecision);
+ virtual void visitSymbol(TIntermSymbol* node);
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_
diff --git a/src/compiler/OutputGLSLBase.cpp b/src/compiler/OutputGLSLBase.cpp
new file mode 100644
index 00000000..d677c756
--- /dev/null
+++ b/src/compiler/OutputGLSLBase.cpp
@@ -0,0 +1,817 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputGLSLBase.h"
+#include "compiler/debug.h"
+
+#include <cfloat>
+
+namespace
+{
+TString arrayBrackets(const TType& type)
+{
+ ASSERT(type.isArray());
+ TInfoSinkBase out;
+ out << "[" << type.getArraySize() << "]";
+ return TString(out.c_str());
+}
+
+bool isSingleStatement(TIntermNode* node) {
+ if (const TIntermAggregate* aggregate = node->getAsAggregate())
+ {
+ return (aggregate->getOp() != EOpFunction) &&
+ (aggregate->getOp() != EOpSequence);
+ }
+ else if (const TIntermSelection* selection = node->getAsSelectionNode())
+ {
+ // Ternary operators are usually part of an assignment operator.
+ // This handles those rare cases in which they are all by themselves.
+ return selection->usesTernaryOperator();
+ }
+ else if (node->getAsLoopNode())
+ {
+ return false;
+ }
+ return true;
+}
+} // namespace
+
+TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable)
+ : TIntermTraverser(true, true, true),
+ mObjSink(objSink),
+ mDeclaringVariables(false),
+ mClampingStrategy(clampingStrategy),
+ mHashFunction(hashFunction),
+ mNameMap(nameMap),
+ mSymbolTable(symbolTable)
+{
+}
+
+void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
+{
+ TInfoSinkBase& out = objSink();
+ if (visit == PreVisit && preStr)
+ {
+ out << preStr;
+ }
+ else if (visit == InVisit && inStr)
+ {
+ out << inStr;
+ }
+ else if (visit == PostVisit && postStr)
+ {
+ out << postStr;
+ }
+}
+
+void TOutputGLSLBase::writeVariableType(const TType& type)
+{
+ TInfoSinkBase& out = objSink();
+ TQualifier qualifier = type.getQualifier();
+ // TODO(alokp): Validate qualifier for variable declarations.
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
+ out << type.getQualifierString() << " ";
+ // Declare the struct if we have not done so already.
+ if ((type.getBasicType() == EbtStruct) && !structDeclared(type.getStruct()))
+ {
+ declareStruct(type.getStruct());
+ }
+ else
+ {
+ if (writeVariablePrecision(type.getPrecision()))
+ out << " ";
+ out << getTypeName(type);
+ }
+}
+
+void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
+{
+ TInfoSinkBase& out = objSink();
+ for (TIntermSequence::const_iterator iter = args.begin();
+ iter != args.end(); ++iter)
+ {
+ const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
+ ASSERT(arg != NULL);
+
+ const TType& type = arg->getType();
+ writeVariableType(type);
+
+ const TString& name = arg->getSymbol();
+ if (!name.empty())
+ out << " " << hashName(name);
+ if (type.isArray())
+ out << arrayBrackets(type);
+
+ // Put a comma if this is not the last argument.
+ if (iter != args.end() - 1)
+ out << ", ";
+ }
+}
+
+const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
+ const ConstantUnion* pConstUnion)
+{
+ TInfoSinkBase& out = objSink();
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ const TStructure* structure = type.getStruct();
+ out << hashName(structure->name()) << "(";
+
+ const TFieldList& fields = structure->fields();
+ for (size_t i = 0; i < fields.size(); ++i)
+ {
+ const TType* fieldType = fields[i]->type();
+ ASSERT(fieldType != NULL);
+ pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
+ if (i != fields.size() - 1) out << ", ";
+ }
+ out << ")";
+ }
+ else
+ {
+ size_t size = type.getObjectSize();
+ bool writeType = size > 1;
+ if (writeType) out << getTypeName(type) << "(";
+ for (size_t i = 0; i < size; ++i, ++pConstUnion)
+ {
+ switch (pConstUnion->getType())
+ {
+ case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); break;
+ case EbtInt: out << pConstUnion->getIConst(); break;
+ case EbtBool: out << pConstUnion->getBConst(); break;
+ default: UNREACHABLE();
+ }
+ if (i != size - 1) out << ", ";
+ }
+ if (writeType) out << ")";
+ }
+ return pConstUnion;
+}
+
+void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
+{
+ TInfoSinkBase& out = objSink();
+ if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
+ out << mLoopUnroll.GetLoopIndexValue(node);
+ else
+ out << hashVariableName(node->getSymbol());
+
+ if (mDeclaringVariables && node->getType().isArray())
+ out << arrayBrackets(node->getType());
+}
+
+void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
+{
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+}
+
+bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase& out = objSink();
+ switch (node->getOp())
+ {
+ case EOpInitialize:
+ if (visit == InVisit)
+ {
+ out << " = ";
+ // RHS of initialize is not being declared.
+ mDeclaringVariables = false;
+ }
+ break;
+ case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
+ case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
+ case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
+ case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
+ // Notice the fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ writeTriplet(visit, "(", " *= ", ")");
+ break;
+
+ case EOpIndexDirect:
+ writeTriplet(visit, NULL, "[", "]");
+ break;
+ case EOpIndexIndirect:
+ if (node->getAddIndexClamp())
+ {
+ if (visit == InVisit)
+ {
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
+ out << "[int(clamp(float(";
+ } else {
+ out << "[webgl_int_clamp(";
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ int maxSize;
+ TIntermTyped *left = node->getLeft();
+ TType leftType = left->getType();
+
+ if (left->isArray())
+ {
+ // The shader will fail validation if the array length is not > 0.
+ maxSize = leftType.getArraySize() - 1;
+ }
+ else
+ {
+ maxSize = leftType.getNominalSize() - 1;
+ }
+
+ if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
+ out << "), 0.0, float(" << maxSize << ")))]";
+ } else {
+ out << ", 0, " << maxSize << ")]";
+ }
+ }
+ }
+ else
+ {
+ writeTriplet(visit, NULL, "[", "]");
+ }
+ break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ // Here we are writing out "foo.bar", where "foo" is struct
+ // and "bar" is field. In AST, it is represented as a binary
+ // node, where left child represents "foo" and right child "bar".
+ // The node itself represents ".". The struct field "bar" is
+ // actually stored as an index into TStructure::fields.
+ out << ".";
+ const TStructure* structure = node->getLeft()->getType().getStruct();
+ const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
+ const TField* field = structure->fields()[index->getIConst(0)];
+
+ TString fieldName = field->name();
+ if (!mSymbolTable.findBuiltIn(structure->name()))
+ fieldName = hashName(fieldName);
+
+ out << fieldName;
+ visitChildren = false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+ TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
+ TIntermSequence& sequence = rightChild->getSequence();
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
+ {
+ TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
+ ASSERT(element->getBasicType() == EbtInt);
+ ASSERT(element->getNominalSize() == 1);
+ const ConstantUnion& data = element->getUnionArrayPointer()[0];
+ ASSERT(data.getType() == EbtInt);
+ switch (data.getIConst())
+ {
+ case 0: out << "x"; break;
+ case 1: out << "y"; break;
+ case 2: out << "z"; break;
+ case 3: out << "w"; break;
+ default: UNREACHABLE(); break;
+ }
+ }
+ visitChildren = false;
+ }
+ break;
+
+ case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
+ case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
+ case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
+ case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
+ case EOpMod: UNIMPLEMENTED(); break;
+ case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
+ case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
+ case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
+
+ // Notice the fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
+
+ case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
+ case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
+ case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
+ default: UNREACHABLE(); break;
+ }
+
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TString preString;
+ TString postString = ")";
+
+ switch (node->getOp())
+ {
+ case EOpNegative: preString = "(-"; break;
+ case EOpVectorLogicalNot: preString = "not("; break;
+ case EOpLogicalNot: preString = "(!"; break;
+
+ case EOpPostIncrement: preString = "("; postString = "++)"; break;
+ case EOpPostDecrement: preString = "("; postString = "--)"; break;
+ case EOpPreIncrement: preString = "(++"; break;
+ case EOpPreDecrement: preString = "(--"; break;
+
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: preString = "bool("; break;
+ case 2: preString = "bvec2("; break;
+ case 3: preString = "bvec3("; break;
+ case 4: preString = "bvec4("; break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: preString = "float("; break;
+ case 2: preString = "vec2("; break;
+ case 3: preString = "vec3("; break;
+ case 4: preString = "vec4("; break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: preString = "int("; break;
+ case 2: preString = "ivec2("; break;
+ case 3: preString = "ivec3("; break;
+ case 4: preString = "ivec4("; break;
+ default: UNREACHABLE();
+ }
+ break;
+
+ case EOpRadians: preString = "radians("; break;
+ case EOpDegrees: preString = "degrees("; break;
+ case EOpSin: preString = "sin("; break;
+ case EOpCos: preString = "cos("; break;
+ case EOpTan: preString = "tan("; break;
+ case EOpAsin: preString = "asin("; break;
+ case EOpAcos: preString = "acos("; break;
+ case EOpAtan: preString = "atan("; break;
+
+ case EOpExp: preString = "exp("; break;
+ case EOpLog: preString = "log("; break;
+ case EOpExp2: preString = "exp2("; break;
+ case EOpLog2: preString = "log2("; break;
+ case EOpSqrt: preString = "sqrt("; break;
+ case EOpInverseSqrt: preString = "inversesqrt("; break;
+
+ case EOpAbs: preString = "abs("; break;
+ case EOpSign: preString = "sign("; break;
+ case EOpFloor: preString = "floor("; break;
+ case EOpCeil: preString = "ceil("; break;
+ case EOpFract: preString = "fract("; break;
+
+ case EOpLength: preString = "length("; break;
+ case EOpNormalize: preString = "normalize("; break;
+
+ case EOpDFdx: preString = "dFdx("; break;
+ case EOpDFdy: preString = "dFdy("; break;
+ case EOpFwidth: preString = "fwidth("; break;
+
+ case EOpAny: preString = "any("; break;
+ case EOpAll: preString = "all("; break;
+
+ default: UNREACHABLE(); break;
+ }
+
+ if (visit == PreVisit && node->getUseEmulatedFunction())
+ preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
+ writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
+
+ return true;
+}
+
+bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ if (node->usesTernaryOperator())
+ {
+ // Notice two brackets at the beginning and end. The outer ones
+ // encapsulate the whole ternary expression. This preserves the
+ // order of precedence when ternary expressions are used in a
+ // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
+ out << "((";
+ node->getCondition()->traverse(this);
+ out << ") ? (";
+ node->getTrueBlock()->traverse(this);
+ out << ") : (";
+ node->getFalseBlock()->traverse(this);
+ out << "))";
+ }
+ else
+ {
+ out << "if (";
+ node->getCondition()->traverse(this);
+ out << ")\n";
+
+ incrementDepth();
+ visitCodeBlock(node->getTrueBlock());
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+ visitCodeBlock(node->getFalseBlock());
+ }
+ decrementDepth();
+ }
+ return false;
+}
+
+bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase& out = objSink();
+ TString preString;
+ bool delayedWrite = false;
+ switch (node->getOp())
+ {
+ case EOpSequence: {
+ // Scope the sequences except when at the global scope.
+ if (depth > 0) out << "{\n";
+
+ incrementDepth();
+ const TIntermSequence& sequence = node->getSequence();
+ for (TIntermSequence::const_iterator iter = sequence.begin();
+ iter != sequence.end(); ++iter)
+ {
+ TIntermNode* node = *iter;
+ ASSERT(node != NULL);
+ node->traverse(this);
+
+ if (isSingleStatement(node))
+ out << ";\n";
+ }
+ decrementDepth();
+
+ // Scope the sequences except when at the global scope.
+ if (depth > 0) out << "}\n";
+ visitChildren = false;
+ break;
+ }
+ case EOpPrototype: {
+ // Function declaration.
+ ASSERT(visit == PreVisit);
+ writeVariableType(node->getType());
+ out << " " << hashName(node->getName());
+
+ out << "(";
+ writeFunctionParameters(node->getSequence());
+ out << ")";
+
+ visitChildren = false;
+ break;
+ }
+ case EOpFunction: {
+ // Function definition.
+ ASSERT(visit == PreVisit);
+ writeVariableType(node->getType());
+ out << " " << hashFunctionName(node->getName());
+
+ incrementDepth();
+ // Function definition node contains one or two children nodes
+ // representing function parameters and function body. The latter
+ // is not present in case of empty function bodies.
+ const TIntermSequence& sequence = node->getSequence();
+ ASSERT((sequence.size() == 1) || (sequence.size() == 2));
+ TIntermSequence::const_iterator seqIter = sequence.begin();
+
+ // Traverse function parameters.
+ TIntermAggregate* params = (*seqIter)->getAsAggregate();
+ ASSERT(params != NULL);
+ ASSERT(params->getOp() == EOpParameters);
+ params->traverse(this);
+
+ // Traverse function body.
+ TIntermAggregate* body = ++seqIter != sequence.end() ?
+ (*seqIter)->getAsAggregate() : NULL;
+ visitCodeBlock(body);
+ decrementDepth();
+
+ // Fully processed; no need to visit children.
+ visitChildren = false;
+ break;
+ }
+ case EOpFunctionCall:
+ // Function call.
+ if (visit == PreVisit)
+ {
+ out << hashFunctionName(node->getName()) << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ break;
+ case EOpParameters: {
+ // Function parameters.
+ ASSERT(visit == PreVisit);
+ out << "(";
+ writeFunctionParameters(node->getSequence());
+ out << ")";
+ visitChildren = false;
+ break;
+ }
+ case EOpDeclaration: {
+ // Variable declaration.
+ if (visit == PreVisit)
+ {
+ const TIntermSequence& sequence = node->getSequence();
+ const TIntermTyped* variable = sequence.front()->getAsTyped();
+ writeVariableType(variable->getType());
+ out << " ";
+ mDeclaringVariables = true;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ mDeclaringVariables = true;
+ }
+ else
+ {
+ mDeclaringVariables = false;
+ }
+ break;
+ }
+ case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
+ case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
+ case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
+ case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
+ case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
+ case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
+ case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
+ case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
+ case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
+ case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
+ case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
+ case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
+ case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
+ case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
+ case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
+ case EOpConstructStruct:
+ if (visit == PreVisit)
+ {
+ const TType& type = node->getType();
+ ASSERT(type.getBasicType() == EbtStruct);
+ out << hashName(type.getStruct()->name()) << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ break;
+
+ case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
+ case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
+ case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
+ case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
+ case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
+ case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
+ case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
+
+ case EOpMod: preString = "mod("; delayedWrite = true; break;
+ case EOpPow: preString = "pow("; delayedWrite = true; break;
+ case EOpAtan: preString = "atan("; delayedWrite = true; break;
+ case EOpMin: preString = "min("; delayedWrite = true; break;
+ case EOpMax: preString = "max("; delayedWrite = true; break;
+ case EOpClamp: preString = "clamp("; delayedWrite = true; break;
+ case EOpMix: preString = "mix("; delayedWrite = true; break;
+ case EOpStep: preString = "step("; delayedWrite = true; break;
+ case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
+
+ case EOpDistance: preString = "distance("; delayedWrite = true; break;
+ case EOpDot: preString = "dot("; delayedWrite = true; break;
+ case EOpCross: preString = "cross("; delayedWrite = true; break;
+ case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
+ case EOpReflect: preString = "reflect("; delayedWrite = true; break;
+ case EOpRefract: preString = "refract("; delayedWrite = true; break;
+ case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
+
+ default: UNREACHABLE(); break;
+ }
+ if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
+ preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
+ if (delayedWrite)
+ writeTriplet(visit, preString.c_str(), ", ", ")");
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ incrementDepth();
+ // Loop header.
+ TLoopType loopType = node->getType();
+ if (loopType == ELoopFor) // for loop
+ {
+ if (!node->getUnrollFlag()) {
+ out << "for (";
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ out << "; ";
+
+ if (node->getCondition())
+ node->getCondition()->traverse(this);
+ out << "; ";
+
+ if (node->getExpression())
+ node->getExpression()->traverse(this);
+ out << ")\n";
+ }
+ }
+ else if (loopType == ELoopWhile) // while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != NULL);
+ node->getCondition()->traverse(this);
+ out << ")\n";
+ }
+ else // do-while loop
+ {
+ ASSERT(loopType == ELoopDoWhile);
+ out << "do\n";
+ }
+
+ // Loop body.
+ if (node->getUnrollFlag())
+ {
+ TLoopIndexInfo indexInfo;
+ mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
+ mLoopUnroll.Push(indexInfo);
+ while (mLoopUnroll.SatisfiesLoopCondition())
+ {
+ visitCodeBlock(node->getBody());
+ mLoopUnroll.Step();
+ }
+ mLoopUnroll.Pop();
+ }
+ else
+ {
+ visitCodeBlock(node->getBody());
+ }
+
+ // Loop footer.
+ if (loopType == ELoopDoWhile) // do-while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != NULL);
+ node->getCondition()->traverse(this);
+ out << ");\n";
+ }
+ decrementDepth();
+
+ // No need to visit children. They have been already processed in
+ // this function.
+ return false;
+}
+
+bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
+{
+ switch (node->getFlowOp())
+ {
+ case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
+ case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
+ case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
+ case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
+ default: UNREACHABLE(); break;
+ }
+
+ return true;
+}
+
+void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
+ TInfoSinkBase &out = objSink();
+ if (node != NULL)
+ {
+ node->traverse(this);
+ // Single statements not part of a sequence need to be terminated
+ // with semi-colon.
+ if (isSingleStatement(node))
+ out << ";\n";
+ }
+ else
+ {
+ out << "{\n}\n"; // Empty code block.
+ }
+}
+
+TString TOutputGLSLBase::getTypeName(const TType& type)
+{
+ TInfoSinkBase out;
+ if (type.isMatrix())
+ {
+ out << "mat";
+ out << type.getNominalSize();
+ }
+ else if (type.isVector())
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat: out << "vec"; break;
+ case EbtInt: out << "ivec"; break;
+ case EbtBool: out << "bvec"; break;
+ default: UNREACHABLE(); break;
+ }
+ out << type.getNominalSize();
+ }
+ else
+ {
+ if (type.getBasicType() == EbtStruct)
+ out << hashName(type.getStruct()->name());
+ else
+ out << type.getBasicString();
+ }
+ return TString(out.c_str());
+}
+
+TString TOutputGLSLBase::hashName(const TString& name)
+{
+ if (mHashFunction == NULL || name.empty())
+ return name;
+ NameMap::const_iterator it = mNameMap.find(name.c_str());
+ if (it != mNameMap.end())
+ return it->second.c_str();
+ TString hashedName = TIntermTraverser::hash(name, mHashFunction);
+ mNameMap[name.c_str()] = hashedName.c_str();
+ return hashedName;
+}
+
+TString TOutputGLSLBase::hashVariableName(const TString& name)
+{
+ if (mSymbolTable.findBuiltIn(name) != NULL)
+ return name;
+ return hashName(name);
+}
+
+TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
+{
+ TString name = TFunction::unmangleName(mangled_name);
+ if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
+ return name;
+ return hashName(name);
+}
+
+bool TOutputGLSLBase::structDeclared(const TStructure* structure) const
+{
+ return mDeclaredStructs.find(structure->name()) != mDeclaredStructs.end();
+}
+
+void TOutputGLSLBase::declareStruct(const TStructure* structure)
+{
+ TInfoSinkBase& out = objSink();
+
+ out << "struct " << hashName(structure->name()) << "{\n";
+ const TFieldList& fields = structure->fields();
+ for (size_t i = 0; i < fields.size(); ++i)
+ {
+ const TField* field = fields[i];
+ if (writeVariablePrecision(field->type()->getPrecision()))
+ out << " ";
+ out << getTypeName(*field->type()) << " " << hashName(field->name());
+ if (field->type()->isArray())
+ out << arrayBrackets(*field->type());
+ out << ";\n";
+ }
+ out << "}";
+
+ mDeclaredStructs.insert(structure->name());
+}
diff --git a/src/compiler/OutputGLSLBase.h b/src/compiler/OutputGLSLBase.h
new file mode 100644
index 00000000..df4ad68c
--- /dev/null
+++ b/src/compiler/OutputGLSLBase.h
@@ -0,0 +1,79 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
+#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
+
+#include <set>
+
+#include "compiler/ForLoopUnroll.h"
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+class TOutputGLSLBase : public TIntermTraverser
+{
+public:
+ TOutputGLSLBase(TInfoSinkBase& objSink,
+ ShArrayIndexClampingStrategy clampingStrategy,
+ ShHashFunction64 hashFunction,
+ NameMap& nameMap,
+ TSymbolTable& symbolTable);
+
+protected:
+ TInfoSinkBase& objSink() { return mObjSink; }
+ void writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr);
+ void writeVariableType(const TType& type);
+ virtual bool writeVariablePrecision(TPrecision precision) = 0;
+ void writeFunctionParameters(const TIntermSequence& args);
+ const ConstantUnion* writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion);
+ TString getTypeName(const TType& type);
+
+ virtual void visitSymbol(TIntermSymbol* node);
+ virtual void visitConstantUnion(TIntermConstantUnion* node);
+ virtual bool visitBinary(Visit visit, TIntermBinary* node);
+ virtual bool visitUnary(Visit visit, TIntermUnary* node);
+ virtual bool visitSelection(Visit visit, TIntermSelection* node);
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node);
+ virtual bool visitLoop(Visit visit, TIntermLoop* node);
+ virtual bool visitBranch(Visit visit, TIntermBranch* node);
+
+ void visitCodeBlock(TIntermNode* node);
+
+
+ // Return the original name if hash function pointer is NULL;
+ // otherwise return the hashed name.
+ TString hashName(const TString& name);
+ // Same as hashName(), but without hashing built-in variables.
+ TString hashVariableName(const TString& name);
+ // Same as hashName(), but without hashing built-in functions.
+ TString hashFunctionName(const TString& mangled_name);
+
+private:
+ bool structDeclared(const TStructure* structure) const;
+ void declareStruct(const TStructure* structure);
+
+ TInfoSinkBase& mObjSink;
+ bool mDeclaringVariables;
+
+ // Structs are declared as the tree is traversed. This set contains all
+ // the structs already declared. It is maintained so that a struct is
+ // declared only once.
+ typedef std::set<TString> DeclaredStructs;
+ DeclaredStructs mDeclaredStructs;
+
+ ForLoopUnroll mLoopUnroll;
+
+ ShArrayIndexClampingStrategy mClampingStrategy;
+
+ // name hashing.
+ ShHashFunction64 mHashFunction;
+
+ NameMap& mNameMap;
+
+ TSymbolTable& mSymbolTable;
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
new file mode 100644
index 00000000..79a373eb
--- /dev/null
+++ b/src/compiler/OutputHLSL.cpp
@@ -0,0 +1,3094 @@
+//
+// 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.
+//
+
+#include "compiler/OutputHLSL.h"
+
+#include "common/angleutils.h"
+#include "compiler/debug.h"
+#include "compiler/DetectDiscontinuity.h"
+#include "compiler/InfoSink.h"
+#include "compiler/SearchSymbol.h"
+#include "compiler/UnfoldShortCircuit.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <stdio.h>
+
+namespace sh
+{
+// Integer to TString conversion
+TString str(int i)
+{
+ char buffer[20];
+ snprintf(buffer, sizeof(buffer), "%d", i);
+ return buffer;
+}
+
+OutputHLSL::OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType)
+ : TIntermTraverser(true, true, true), mContext(context), mOutputType(outputType)
+{
+ mUnfoldShortCircuit = new UnfoldShortCircuit(context, this);
+ mInsideFunction = false;
+
+ mUsesTexture2D = false;
+ mUsesTexture2D_bias = false;
+ mUsesTexture2DProj = false;
+ mUsesTexture2DProj_bias = false;
+ mUsesTexture2DProjLod = false;
+ mUsesTexture2DLod = false;
+ mUsesTextureCube = false;
+ mUsesTextureCube_bias = false;
+ mUsesTextureCubeLod = false;
+ mUsesTexture2DLod0 = false;
+ mUsesTexture2DLod0_bias = false;
+ mUsesTexture2DProjLod0 = false;
+ mUsesTexture2DProjLod0_bias = false;
+ mUsesTextureCubeLod0 = false;
+ mUsesTextureCubeLod0_bias = false;
+ mUsesFragColor = false;
+ mUsesFragData = false;
+ mUsesDepthRange = false;
+ mUsesFragCoord = false;
+ mUsesPointCoord = false;
+ mUsesFrontFacing = false;
+ mUsesPointSize = false;
+ mUsesFragDepth = false;
+ mUsesXor = false;
+ mUsesMod1 = false;
+ mUsesMod2v = false;
+ mUsesMod2f = false;
+ mUsesMod3v = false;
+ mUsesMod3f = false;
+ mUsesMod4v = false;
+ mUsesMod4f = false;
+ mUsesFaceforward1 = false;
+ mUsesFaceforward2 = false;
+ mUsesFaceforward3 = false;
+ mUsesFaceforward4 = false;
+ mUsesAtan2_1 = false;
+ mUsesAtan2_2 = false;
+ mUsesAtan2_3 = false;
+ mUsesAtan2_4 = false;
+
+ mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
+
+ mScopeDepth = 0;
+
+ mUniqueIndex = 0;
+
+ mContainsLoopDiscontinuity = false;
+ mOutputLod0Function = false;
+ mInsideDiscontinuousLoop = false;
+
+ mExcessiveLoopIndex = NULL;
+
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ if (mContext.shaderType == SH_FRAGMENT_SHADER)
+ {
+ mUniformRegister = 3; // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront
+ }
+ else
+ {
+ mUniformRegister = 2; // Reserve registers for dx_DepthRange and dx_ViewAdjust
+ }
+ }
+ else
+ {
+ mUniformRegister = 0;
+ }
+
+ mSamplerRegister = 0;
+}
+
+OutputHLSL::~OutputHLSL()
+{
+ delete mUnfoldShortCircuit;
+}
+
+void OutputHLSL::output()
+{
+ mContainsLoopDiscontinuity = mContext.shaderType == SH_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot);
+
+ mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
+ header();
+
+ mContext.infoSink().obj << mHeader.c_str();
+ mContext.infoSink().obj << mBody.c_str();
+}
+
+TInfoSinkBase &OutputHLSL::getBodyStream()
+{
+ return mBody;
+}
+
+const ActiveUniforms &OutputHLSL::getUniforms()
+{
+ return mActiveUniforms;
+}
+
+int OutputHLSL::vectorSize(const TType &type) const
+{
+ int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
+ int arraySize = type.isArray() ? type.getArraySize() : 1;
+
+ return elementSize * arraySize;
+}
+
+void OutputHLSL::header()
+{
+ ShShaderType shaderType = mContext.shaderType;
+ TInfoSinkBase &out = mHeader;
+
+ for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
+ {
+ out << *structDeclaration;
+ }
+
+ for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
+ {
+ out << *constructor;
+ }
+
+ TString uniforms;
+ TString varyings;
+ TString attributes;
+
+ for (ReferencedSymbols::const_iterator uniform = mReferencedUniforms.begin(); uniform != mReferencedUniforms.end(); uniform++)
+ {
+ const TType &type = uniform->second->getType();
+ const TString &name = uniform->second->getSymbol();
+
+ if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType())) // Also declare the texture
+ {
+ int index = samplerRegister(mReferencedUniforms[name]);
+
+ uniforms += "uniform SamplerState sampler_" + decorateUniform(name, type) + arrayString(type) +
+ " : register(s" + str(index) + ");\n";
+
+ uniforms += "uniform " + textureString(type) + " texture_" + decorateUniform(name, type) + arrayString(type) +
+ " : register(t" + str(index) + ");\n";
+ }
+ else
+ {
+ uniforms += "uniform " + typeString(type) + " " + decorateUniform(name, type) + arrayString(type) +
+ " : register(" + registerString(mReferencedUniforms[name]) + ");\n";
+ }
+ }
+
+ for (ReferencedSymbols::const_iterator varying = mReferencedVaryings.begin(); varying != mReferencedVaryings.end(); varying++)
+ {
+ const TType &type = varying->second->getType();
+ const TString &name = varying->second->getSymbol();
+
+ // Program linking depends on this exact format
+ varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+ }
+
+ for (ReferencedSymbols::const_iterator attribute = mReferencedAttributes.begin(); attribute != mReferencedAttributes.end(); attribute++)
+ {
+ const TType &type = attribute->second->getType();
+ const TString &name = attribute->second->getSymbol();
+
+ attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+ }
+
+ if (shaderType == SH_FRAGMENT_SHADER)
+ {
+ TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers");
+ const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire));
+
+ const unsigned int numColorValues = usingMRTExtension ? mNumRenderTargets : 1;
+
+ out << "// Varyings\n";
+ out << varyings;
+ out << "\n"
+ "static float4 gl_Color[" << numColorValues << "] =\n"
+ "{\n";
+ for (unsigned int i = 0; i < numColorValues; i++)
+ {
+ out << " float4(0, 0, 0, 0)";
+ if (i + 1 != numColorValues)
+ {
+ out << ",";
+ }
+ out << "\n";
+ }
+ out << "};\n";
+
+ if (mUsesFragDepth)
+ {
+ out << "static float gl_Depth = 0.0;\n";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "static bool gl_FrontFacing = false;\n";
+ }
+
+ out << "\n";
+
+ if (mUsesDepthRange)
+ {
+ out << "struct gl_DepthRangeParameters\n"
+ "{\n"
+ " float near;\n"
+ " float far;\n"
+ " float diff;\n"
+ "};\n"
+ "\n";
+ }
+
+ if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "cbuffer DriverConstants : register(b1)\n"
+ "{\n";
+
+ if (mUsesDepthRange)
+ {
+ out << " float3 dx_DepthRange : packoffset(c0);\n";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << " float4 dx_ViewCoords : packoffset(c1);\n";
+ }
+
+ if (mUsesFragCoord || mUsesFrontFacing)
+ {
+ out << " float3 dx_DepthFront : packoffset(c2);\n";
+ }
+
+ out << "};\n";
+ }
+ else
+ {
+ if (mUsesDepthRange)
+ {
+ out << "uniform float3 dx_DepthRange : register(c0);";
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "uniform float4 dx_ViewCoords : register(c1);\n";
+ }
+
+ if (mUsesFragCoord || mUsesFrontFacing)
+ {
+ out << "uniform float3 dx_DepthFront : register(c2);\n";
+ }
+ }
+
+ out << "\n";
+
+ if (mUsesDepthRange)
+ {
+ out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
+ "\n";
+ }
+
+ out << uniforms;
+ out << "\n";
+
+ if (mUsesTexture2D)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
+ "{\n"
+ " return tex2D(s, t);\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv)\n"
+ "{\n"
+ " return t.Sample(s, uv);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTexture2D_bias)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
+ "{\n"
+ " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv, float bias)\n"
+ "{\n"
+ " return t.SampleBias(s, uv, bias);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTexture2DProj)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
+ "{\n"
+ " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
+ "{\n"
+ " return tex2Dproj(s, t);\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw)\n"
+ "{\n"
+ " return t.Sample(s, float2(uvw.x / uvw.z, uvw.y / uvw.z));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n"
+ "{\n"
+ " return t.Sample(s, float2(uvw.x / uvw.w, uvw.y / uvw.w));\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTexture2DProj_bias)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
+ "{\n"
+ " return tex2Dbias(s, float4(t.x / t.z, t.y / t.z, 0, bias));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
+ "{\n"
+ " return tex2Dbias(s, float4(t.x / t.w, t.y / t.w, 0, bias));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw, float bias)\n"
+ "{\n"
+ " return t.SampleBias(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), bias);\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw, float bias)\n"
+ "{\n"
+ " return t.SampleBias(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), bias);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTextureCube)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
+ "{\n"
+ " return texCUBE(s, t);\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw)\n"
+ "{\n"
+ " return t.Sample(s, uvw);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTextureCube_bias)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
+ "{\n"
+ " return texCUBEbias(s, float4(t.x, t.y, t.z, bias));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw, float bias)\n"
+ "{\n"
+ " return t.SampleBias(s, uvw, bias);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ // These *Lod0 intrinsics are not available in GL fragment shaders.
+ // They are used to sample using discontinuous texture coordinates.
+ if (mUsesTexture2DLod0)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2DLod0(sampler2D s, float2 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2DLod0(Texture2D t, SamplerState s, float2 uv)\n"
+ "{\n"
+ " return t.SampleLevel(s, uv, 0);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTexture2DLod0_bias)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2DLod0(sampler2D s, float2 t, float bias)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2DLod0(Texture2D t, SamplerState s, float2 uv, float bias)\n"
+ "{\n"
+ " return t.SampleLevel(s, uv, 0);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTexture2DProjLod0)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2DProjLod0(sampler2D s, float3 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProjLod(sampler2D s, float4 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2DProjLod0(Texture2D t, SamplerState s, float3 uvw)\n"
+ "{\n"
+ " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProjLod0(Texture2D t, SamplerState s, float4 uvw)\n"
+ "{\n"
+ " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTexture2DProjLod0_bias)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2DProjLod0_bias(sampler2D s, float3 t, float bias)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProjLod_bias(sampler2D s, float4 t, float bias)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2DProjLod_bias(Texture2D t, SamplerState s, float3 uvw, float bias)\n"
+ "{\n"
+ " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProjLod_bias(Texture2D t, SamplerState s, float4 uvw, float bias)\n"
+ "{\n"
+ " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTextureCubeLod0)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_textureCubeLod0(TextureCube t, SamplerState s, float3 uvw)\n"
+ "{\n"
+ " return t.SampleLevel(s, uvw, 0);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTextureCubeLod0_bias)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_textureCubeLod0(samplerCUBE s, float3 t, float bias)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_textureCubeLod0(TextureCube t, SamplerState s, float3 uvw, float bias)\n"
+ "{\n"
+ " return t.SampleLevel(s, uvw, 0);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (usingMRTExtension && mNumRenderTargets > 1)
+ {
+ out << "#define GL_USES_MRT\n";
+ }
+
+ if (mUsesFragColor)
+ {
+ out << "#define GL_USES_FRAG_COLOR\n";
+ }
+
+ if (mUsesFragData)
+ {
+ out << "#define GL_USES_FRAG_DATA\n";
+ }
+ }
+ else // Vertex shader
+ {
+ out << "// Attributes\n";
+ out << attributes;
+ out << "\n"
+ "static float4 gl_Position = float4(0, 0, 0, 0);\n";
+
+ if (mUsesPointSize)
+ {
+ out << "static float gl_PointSize = float(1);\n";
+ }
+
+ out << "\n"
+ "// Varyings\n";
+ out << varyings;
+ out << "\n";
+
+ if (mUsesDepthRange)
+ {
+ out << "struct gl_DepthRangeParameters\n"
+ "{\n"
+ " float near;\n"
+ " float far;\n"
+ " float diff;\n"
+ "};\n"
+ "\n";
+ }
+
+ if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ if (mUsesDepthRange)
+ {
+ out << "cbuffer DriverConstants : register(b1)\n"
+ "{\n"
+ " float3 dx_DepthRange : packoffset(c0);\n"
+ "};\n"
+ "\n";
+ }
+ }
+ else
+ {
+ if (mUsesDepthRange)
+ {
+ out << "uniform float3 dx_DepthRange : register(c0);\n";
+ }
+
+ out << "uniform float4 dx_ViewAdjust : register(c1);\n"
+ "\n";
+ }
+
+ if (mUsesDepthRange)
+ {
+ out << "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
+ "\n";
+ }
+
+ out << uniforms;
+ out << "\n";
+
+ if (mUsesTexture2D)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, t.y, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2D(Texture2D t, SamplerState s, float2 uv)\n"
+ "{\n"
+ " return t.SampleLevel(s, uv, 0);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTexture2DLod)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, t.y, 0, lod));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2DLod(Texture2D t, SamplerState s, float2 uv, float lod)\n"
+ "{\n"
+ " return t.SampleLevel(s, uv, lod);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTexture2DProj)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, 0));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw)\n"
+ "{\n"
+ " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), 0);\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n"
+ "{\n"
+ " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), 0);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTexture2DProjLod)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, t.y / t.z, 0, lod));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, t.y / t.w, 0, lod));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_texture2DProj(Texture2D t, SamplerState s, float3 uvw, float lod)\n"
+ "{\n"
+ " return t.SampleLevel(s, float2(uvw.x / uvw.z, uvw.y / uvw.z), lod);\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(Texture2D t, SamplerState s, float4 uvw)\n"
+ "{\n"
+ " return t.SampleLevel(s, float2(uvw.x / uvw.w, uvw.y / uvw.w), lod);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTextureCube)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, t.y, t.z, 0));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_textureCube(TextureCube t, SamplerState s, float3 uvw)\n"
+ "{\n"
+ " return t.SampleLevel(s, uvw, 0);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+
+ if (mUsesTextureCubeLod)
+ {
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, t.y, t.z, lod));\n"
+ "}\n"
+ "\n";
+ }
+ else if (mOutputType == SH_HLSL11_OUTPUT)
+ {
+ out << "float4 gl_textureCubeLod(TextureCube t, SamplerState s, float3 uvw, float lod)\n"
+ "{\n"
+ " return t.SampleLevel(s, uvw, lod);\n"
+ "}\n"
+ "\n";
+ }
+ else UNREACHABLE();
+ }
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "#define GL_USES_FRAG_COORD\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "#define GL_USES_POINT_COORD\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "#define GL_USES_FRONT_FACING\n";
+ }
+
+ if (mUsesPointSize)
+ {
+ out << "#define GL_USES_POINT_SIZE\n";
+ }
+
+ if (mUsesFragDepth)
+ {
+ out << "#define GL_USES_FRAG_DEPTH\n";
+ }
+
+ if (mUsesDepthRange)
+ {
+ out << "#define GL_USES_DEPTH_RANGE\n";
+ }
+
+ if (mUsesXor)
+ {
+ out << "bool xor(bool p, bool q)\n"
+ "{\n"
+ " return (p || q) && !(p && q);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod1)
+ {
+ out << "float mod(float x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod2v)
+ {
+ out << "float2 mod(float2 x, float2 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod2f)
+ {
+ out << "float2 mod(float2 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod3v)
+ {
+ out << "float3 mod(float3 x, float3 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod3f)
+ {
+ out << "float3 mod(float3 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod4v)
+ {
+ out << "float4 mod(float4 x, float4 y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod4f)
+ {
+ out << "float4 mod(float4 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward1)
+ {
+ out << "float faceforward(float N, float I, float Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward2)
+ {
+ out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward3)
+ {
+ out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward4)
+ {
+ out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesAtan2_1)
+ {
+ out << "float atanyx(float y, float x)\n"
+ "{\n"
+ " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
+ " return atan2(y, x);\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_2)
+ {
+ out << "float2 atanyx(float2 y, float2 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " return float2(atan2(y[0], x[0]), atan2(y[1], x[1]));\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_3)
+ {
+ out << "float3 atanyx(float3 y, float3 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
+ " return float3(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]));\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2_4)
+ {
+ out << "float4 atanyx(float4 y, float4 x)\n"
+ "{\n"
+ " if(x[0] == 0 && y[0] == 0) x[0] = 1;\n"
+ " if(x[1] == 0 && y[1] == 0) x[1] = 1;\n"
+ " if(x[2] == 0 && y[2] == 0) x[2] = 1;\n"
+ " if(x[3] == 0 && y[3] == 0) x[3] = 1;\n"
+ " return float4(atan2(y[0], x[0]), atan2(y[1], x[1]), atan2(y[2], x[2]), atan2(y[3], x[3]));\n"
+ "}\n";
+ }
+}
+
+void OutputHLSL::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ TString name = node->getSymbol();
+
+ if (name == "gl_FragColor")
+ {
+ out << "gl_Color[0]";
+ mUsesFragColor = true;
+ }
+ else if (name == "gl_FragData")
+ {
+ out << "gl_Color";
+ mUsesFragData = true;
+ }
+ else if (name == "gl_DepthRange")
+ {
+ mUsesDepthRange = true;
+ out << name;
+ }
+ else if (name == "gl_FragCoord")
+ {
+ mUsesFragCoord = true;
+ out << name;
+ }
+ else if (name == "gl_PointCoord")
+ {
+ mUsesPointCoord = true;
+ out << name;
+ }
+ else if (name == "gl_FrontFacing")
+ {
+ mUsesFrontFacing = true;
+ out << name;
+ }
+ else if (name == "gl_PointSize")
+ {
+ mUsesPointSize = true;
+ out << name;
+ }
+ else if (name == "gl_FragDepthEXT")
+ {
+ mUsesFragDepth = true;
+ out << "gl_Depth";
+ }
+ else
+ {
+ TQualifier qualifier = node->getQualifier();
+
+ if (qualifier == EvqUniform)
+ {
+ mReferencedUniforms[name] = node;
+ out << decorateUniform(name, node->getType());
+ }
+ else if (qualifier == EvqAttribute)
+ {
+ mReferencedAttributes[name] = node;
+ out << decorate(name);
+ }
+ else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
+ {
+ mReferencedVaryings[name] = node;
+ out << decorate(name);
+ }
+ else
+ {
+ out << decorate(name);
+ }
+ }
+}
+
+bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getOp())
+ {
+ case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
+ case EOpInitialize:
+ if (visit == PreVisit)
+ {
+ // GLSL allows to write things like "float x = x;" where a new variable x is defined
+ // and the value of an existing variable x is assigned. HLSL uses C semantics (the
+ // new variable is created before the assignment is evaluated), so we need to convert
+ // this to "float t = x, x = t;".
+
+ TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
+ TIntermTyped *expression = node->getRight();
+
+ sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
+ expression->traverse(&searchSymbol);
+ bool sameSymbol = searchSymbol.foundMatch();
+
+ if (sameSymbol)
+ {
+ // Type already printed
+ out << "t" + str(mUniqueIndex) + " = ";
+ expression->traverse(this);
+ out << ", ";
+ symbolNode->traverse(this);
+ out << " = t" + str(mUniqueIndex);
+
+ mUniqueIndex++;
+ return false;
+ }
+ }
+ else if (visit == InVisit)
+ {
+ out << " = ";
+ }
+ break;
+ case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
+ case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
+ case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpVectorTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = mul(";
+ node->getLeft()->traverse(this);
+ out << ", transpose(";
+ }
+ else
+ {
+ out << ")))";
+ }
+ break;
+ case EOpMatrixTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = mul(";
+ node->getLeft()->traverse(this);
+ out << ", ";
+ }
+ else
+ {
+ out << "))";
+ }
+ break;
+ case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
+ case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
+ case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ const TStructure* structure = node->getLeft()->getType().getStruct();
+ const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
+ const TField* field = structure->fields()[index->getIConst(0)];
+ out << "." + decorateField(field->name(), node->getLeft()->getType());
+
+ return false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+
+ TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
+
+ if (swizzle)
+ {
+ TIntermSequence &sequence = swizzle->getSequence();
+
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
+
+ if (element)
+ {
+ int i = element->getIConst(0);
+
+ switch (i)
+ {
+ case 0: out << "x"; break;
+ case 1: out << "y"; break;
+ case 2: out << "z"; break;
+ case 3: out << "w"; break;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+
+ return false; // Fully processed
+ }
+ break;
+ case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
+ case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
+ case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
+ case EOpEqual:
+ case EOpNotEqual:
+ if (node->getLeft()->isScalar())
+ {
+ if (node->getOp() == EOpEqual)
+ {
+ outputTriplet(visit, "(", " == ", ")");
+ }
+ else
+ {
+ outputTriplet(visit, "(", " != ", ")");
+ }
+ }
+ else if (node->getLeft()->getBasicType() == EbtStruct)
+ {
+ if (node->getOp() == EOpEqual)
+ {
+ out << "(";
+ }
+ else
+ {
+ out << "!(";
+ }
+
+ const TFieldList &fields = node->getLeft()->getType().getStruct()->fields();
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ const TField *field = fields[i];
+
+ node->getLeft()->traverse(this);
+ out << "." + decorateField(field->name(), node->getLeft()->getType()) + " == ";
+ node->getRight()->traverse(this);
+ out << "." + decorateField(field->name(), node->getLeft()->getType());
+
+ if (i < fields.size() - 1)
+ {
+ out << " && ";
+ }
+ }
+
+ out << ")";
+
+ return false;
+ }
+ else
+ {
+ ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector());
+
+ if (node->getOp() == EOpEqual)
+ {
+ outputTriplet(visit, "all(", " == ", ")");
+ }
+ else
+ {
+ outputTriplet(visit, "!all(", " == ", ")");
+ }
+ }
+ break;
+ case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
+ case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
+ case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
+ case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
+ case EOpLogicalOr:
+ out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
+ return false;
+ case EOpLogicalXor:
+ mUsesXor = true;
+ outputTriplet(visit, "xor(", ", ", ")");
+ break;
+ case EOpLogicalAnd:
+ out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
+ return false;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
+{
+ switch (node->getOp())
+ {
+ case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
+ case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
+ case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
+ case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
+ case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
+ case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
+ case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "bool(", "", ")"); break;
+ case 2: outputTriplet(visit, "bool2(", "", ")"); break;
+ case 3: outputTriplet(visit, "bool3(", "", ")"); break;
+ case 4: outputTriplet(visit, "bool4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "float(", "", ")"); break;
+ case 2: outputTriplet(visit, "float2(", "", ")"); break;
+ case 3: outputTriplet(visit, "float3(", "", ")"); break;
+ case 4: outputTriplet(visit, "float4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "int(", "", ")"); break;
+ case 2: outputTriplet(visit, "int2(", "", ")"); break;
+ case 3: outputTriplet(visit, "int3(", "", ")"); break;
+ case 4: outputTriplet(visit, "int4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
+ case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
+ case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
+ case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
+ case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
+ case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
+ case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
+ case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
+ case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
+ case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
+ case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
+ case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
+ case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
+ case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
+ case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
+ case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
+ case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
+ case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
+ case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
+ case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
+ case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
+ case EOpDFdx:
+ if(mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(visit, "ddx(", "", ")");
+ }
+ break;
+ case EOpDFdy:
+ if(mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(visit, "ddy(", "", ")");
+ }
+ break;
+ case EOpFwidth:
+ if(mInsideDiscontinuousLoop || mOutputLod0Function)
+ {
+ outputTriplet(visit, "(", "", ", 0.0)");
+ }
+ else
+ {
+ outputTriplet(visit, "fwidth(", "", ")");
+ }
+ break;
+ case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
+ case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ {
+ if (mInsideFunction)
+ {
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+
+ mScopeDepth++;
+
+ if (mScopeBracket.size() < mScopeDepth)
+ {
+ mScopeBracket.push_back(0); // New scope level
+ }
+ else
+ {
+ mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
+ }
+ }
+
+ for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
+ {
+ outputLineDirective((*sit)->getLine().first_line);
+
+ traverseStatements(*sit);
+
+ out << ";\n";
+ }
+
+ if (mInsideFunction)
+ {
+ outputLineDirective(node->getLine().last_line);
+ out << "}\n";
+
+ mScopeDepth--;
+ }
+
+ return false;
+ }
+ case EOpDeclaration:
+ if (visit == PreVisit)
+ {
+ TIntermSequence &sequence = node->getSequence();
+ TIntermTyped *variable = sequence[0]->getAsTyped();
+
+ if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
+ {
+ if (variable->getType().getStruct())
+ {
+ addConstructor(variable->getType(), scopedStruct(variable->getType().getStruct()->name()), NULL);
+ }
+
+ if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
+ {
+ if (!mInsideFunction)
+ {
+ out << "static ";
+ }
+
+ out << typeString(variable->getType()) + " ";
+
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
+
+ if (symbol)
+ {
+ symbol->traverse(this);
+ out << arrayString(symbol->getType());
+ out << " = " + initializer(variable->getType());
+ }
+ else
+ {
+ (*sit)->traverse(this);
+ }
+
+ if (*sit != sequence.back())
+ {
+ out << ", ";
+ }
+ }
+ }
+ else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
+ {
+ // Already added to constructor map
+ }
+ else UNREACHABLE();
+ }
+ else if (variable && (variable->getQualifier() == EvqVaryingOut || variable->getQualifier() == EvqInvariantVaryingOut))
+ {
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
+
+ if (symbol)
+ {
+ // Vertex (output) varyings which are declared but not written to should still be declared to allow successful linking
+ mReferencedVaryings[symbol->getSymbol()] = symbol;
+ }
+ else
+ {
+ (*sit)->traverse(this);
+ }
+ }
+ }
+
+ return false;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ break;
+ case EOpPrototype:
+ if (visit == PreVisit)
+ {
+ out << typeString(node->getType()) << " " << decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "(");
+
+ TIntermSequence &arguments = node->getSequence();
+
+ for (unsigned int i = 0; i < arguments.size(); i++)
+ {
+ TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ out << argumentString(symbol);
+
+ if (i < arguments.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ out << ");\n";
+
+ // Also prototype the Lod0 variant if needed
+ if (mContainsLoopDiscontinuity && !mOutputLod0Function)
+ {
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+
+ return false;
+ }
+ break;
+ case EOpComma: outputTriplet(visit, "(", ", ", ")"); break;
+ case EOpFunction:
+ {
+ TString name = TFunction::unmangleName(node->getName());
+
+ out << typeString(node->getType()) << " ";
+
+ if (name == "main")
+ {
+ out << "gl_main(";
+ }
+ else
+ {
+ out << decorate(name) << (mOutputLod0Function ? "Lod0(" : "(");
+ }
+
+ TIntermSequence &sequence = node->getSequence();
+ TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
+
+ for (unsigned int i = 0; i < arguments.size(); i++)
+ {
+ TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ if (symbol->getType().getStruct())
+ {
+ addConstructor(symbol->getType(), scopedStruct(symbol->getType().getStruct()->name()), NULL);
+ }
+
+ out << argumentString(symbol);
+
+ if (i < arguments.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ out << ")\n"
+ "{\n";
+
+ if (sequence.size() > 1)
+ {
+ mInsideFunction = true;
+ sequence[1]->traverse(this);
+ mInsideFunction = false;
+ }
+
+ out << "}\n";
+
+ if (mContainsLoopDiscontinuity && !mOutputLod0Function)
+ {
+ if (name != "main")
+ {
+ mOutputLod0Function = true;
+ node->traverse(this);
+ mOutputLod0Function = false;
+ }
+ }
+
+ return false;
+ }
+ break;
+ case EOpFunctionCall:
+ {
+ TString name = TFunction::unmangleName(node->getName());
+ bool lod0 = mInsideDiscontinuousLoop || mOutputLod0Function;
+
+ if (node->isUserDefined())
+ {
+ out << decorate(name) << (lod0 ? "Lod0(" : "(");
+ }
+ else
+ {
+ if (name == "texture2D")
+ {
+ if (!lod0)
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2D = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2D_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2D(";
+ }
+ else
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2DLod0 = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DLod0_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DLod0(";
+ }
+ }
+ else if (name == "texture2DProj")
+ {
+ if (!lod0)
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2DProj = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DProj_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DProj(";
+ }
+ else
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2DProjLod0 = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DProjLod0_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DProjLod0(";
+ }
+ }
+ else if (name == "textureCube")
+ {
+ if (!lod0)
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTextureCube = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTextureCube_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_textureCube(";
+ }
+ else
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTextureCubeLod0 = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTextureCubeLod0_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_textureCubeLod0(";
+ }
+ }
+ else if (name == "texture2DLod")
+ {
+ if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DLod = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DLod(";
+ }
+ else if (name == "texture2DProjLod")
+ {
+ if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DProjLod = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DProjLod(";
+ }
+ else if (name == "textureCubeLod")
+ {
+ if (node->getSequence().size() == 3)
+ {
+ mUsesTextureCubeLod = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_textureCubeLod(";
+ }
+ else UNREACHABLE();
+ }
+
+ TIntermSequence &arguments = node->getSequence();
+
+ for (TIntermSequence::iterator arg = arguments.begin(); arg != arguments.end(); arg++)
+ {
+ if (mOutputType == SH_HLSL11_OUTPUT && IsSampler((*arg)->getAsTyped()->getBasicType()))
+ {
+ out << "texture_";
+ (*arg)->traverse(this);
+ out << ", sampler_";
+ }
+
+ (*arg)->traverse(this);
+
+ if (arg < arguments.end() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")";
+
+ return false;
+ }
+ break;
+ case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
+ case EOpConstructFloat:
+ addConstructor(node->getType(), "vec1", &node->getSequence());
+ outputTriplet(visit, "vec1(", "", ")");
+ break;
+ case EOpConstructVec2:
+ addConstructor(node->getType(), "vec2", &node->getSequence());
+ outputTriplet(visit, "vec2(", ", ", ")");
+ break;
+ case EOpConstructVec3:
+ addConstructor(node->getType(), "vec3", &node->getSequence());
+ outputTriplet(visit, "vec3(", ", ", ")");
+ break;
+ case EOpConstructVec4:
+ addConstructor(node->getType(), "vec4", &node->getSequence());
+ outputTriplet(visit, "vec4(", ", ", ")");
+ break;
+ case EOpConstructBool:
+ addConstructor(node->getType(), "bvec1", &node->getSequence());
+ outputTriplet(visit, "bvec1(", "", ")");
+ break;
+ case EOpConstructBVec2:
+ addConstructor(node->getType(), "bvec2", &node->getSequence());
+ outputTriplet(visit, "bvec2(", ", ", ")");
+ break;
+ case EOpConstructBVec3:
+ addConstructor(node->getType(), "bvec3", &node->getSequence());
+ outputTriplet(visit, "bvec3(", ", ", ")");
+ break;
+ case EOpConstructBVec4:
+ addConstructor(node->getType(), "bvec4", &node->getSequence());
+ outputTriplet(visit, "bvec4(", ", ", ")");
+ break;
+ case EOpConstructInt:
+ addConstructor(node->getType(), "ivec1", &node->getSequence());
+ outputTriplet(visit, "ivec1(", "", ")");
+ break;
+ case EOpConstructIVec2:
+ addConstructor(node->getType(), "ivec2", &node->getSequence());
+ outputTriplet(visit, "ivec2(", ", ", ")");
+ break;
+ case EOpConstructIVec3:
+ addConstructor(node->getType(), "ivec3", &node->getSequence());
+ outputTriplet(visit, "ivec3(", ", ", ")");
+ break;
+ case EOpConstructIVec4:
+ addConstructor(node->getType(), "ivec4", &node->getSequence());
+ outputTriplet(visit, "ivec4(", ", ", ")");
+ break;
+ case EOpConstructMat2:
+ addConstructor(node->getType(), "mat2", &node->getSequence());
+ outputTriplet(visit, "mat2(", ", ", ")");
+ break;
+ case EOpConstructMat3:
+ addConstructor(node->getType(), "mat3", &node->getSequence());
+ outputTriplet(visit, "mat3(", ", ", ")");
+ break;
+ case EOpConstructMat4:
+ addConstructor(node->getType(), "mat4", &node->getSequence());
+ outputTriplet(visit, "mat4(", ", ", ")");
+ break;
+ case EOpConstructStruct:
+ addConstructor(node->getType(), scopedStruct(node->getType().getStruct()->name()), &node->getSequence());
+ outputTriplet(visit, structLookup(node->getType().getStruct()->name()) + "_ctor(", ", ", ")");
+ break;
+ case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
+ case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
+ case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
+ case EOpMod:
+ {
+ // We need to look at the number of components in both arguments
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize() * 10
+ + node->getSequence()[1]->getAsTyped()->getNominalSize())
+ {
+ case 11: mUsesMod1 = true; break;
+ case 22: mUsesMod2v = true; break;
+ case 21: mUsesMod2f = true; break;
+ case 33: mUsesMod3v = true; break;
+ case 31: mUsesMod3f = true; break;
+ case 44: mUsesMod4v = true; break;
+ case 41: mUsesMod4f = true; break;
+ default: UNREACHABLE();
+ }
+
+ outputTriplet(visit, "mod(", ", ", ")");
+ }
+ break;
+ case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
+ case EOpAtan:
+ ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize())
+ {
+ case 1: mUsesAtan2_1 = true; break;
+ case 2: mUsesAtan2_2 = true; break;
+ case 3: mUsesAtan2_3 = true; break;
+ case 4: mUsesAtan2_4 = true; break;
+ default: UNREACHABLE();
+ }
+ outputTriplet(visit, "atanyx(", ", ", ")");
+ break;
+ case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
+ case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
+ case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
+ case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
+ case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
+ case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
+ case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
+ case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
+ case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
+ case EOpFaceForward:
+ {
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
+ {
+ case 1: mUsesFaceforward1 = true; break;
+ case 2: mUsesFaceforward2 = true; break;
+ case 3: mUsesFaceforward3 = true; break;
+ case 4: mUsesFaceforward4 = true; break;
+ default: UNREACHABLE();
+ }
+
+ outputTriplet(visit, "faceforward(", ", ", ")");
+ }
+ break;
+ case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
+ case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
+ case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (node->usesTernaryOperator())
+ {
+ out << "s" << mUnfoldShortCircuit->getNextTemporaryIndex();
+ }
+ else // if/else statement
+ {
+ mUnfoldShortCircuit->traverse(node->getCondition());
+
+ out << "if(";
+
+ node->getCondition()->traverse(this);
+
+ out << ")\n";
+
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+
+ if (node->getTrueBlock())
+ {
+ traverseStatements(node->getTrueBlock());
+ }
+
+ outputLineDirective(node->getLine().first_line);
+ out << ";\n}\n";
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+
+ outputLineDirective(node->getFalseBlock()->getLine().first_line);
+ out << "{\n";
+
+ outputLineDirective(node->getFalseBlock()->getLine().first_line);
+ traverseStatements(node->getFalseBlock());
+
+ outputLineDirective(node->getFalseBlock()->getLine().first_line);
+ out << ";\n}\n";
+ }
+ }
+
+ return false;
+}
+
+void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
+{
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+}
+
+bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
+{
+ bool wasDiscontinuous = mInsideDiscontinuousLoop;
+
+ if (mContainsLoopDiscontinuity && !mInsideDiscontinuousLoop)
+ {
+ mInsideDiscontinuousLoop = containsLoopDiscontinuity(node);
+ }
+
+ if (mOutputType == SH_HLSL9_OUTPUT)
+ {
+ if (handleExcessiveLoop(node))
+ {
+ return false;
+ }
+ }
+
+ TInfoSinkBase &out = mBody;
+
+ if (node->getType() == ELoopDoWhile)
+ {
+ out << "{do\n";
+
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+ }
+ else
+ {
+ out << "{for(";
+
+ if (node->getInit())
+ {
+ node->getInit()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+ }
+
+ out << ")\n";
+
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+ }
+
+ if (node->getBody())
+ {
+ traverseStatements(node->getBody());
+ }
+
+ outputLineDirective(node->getLine().first_line);
+ out << ";}\n";
+
+ if (node->getType() == ELoopDoWhile)
+ {
+ outputLineDirective(node->getCondition()->getLine().first_line);
+ out << "while(\n";
+
+ node->getCondition()->traverse(this);
+
+ out << ");";
+ }
+
+ out << "}\n";
+
+ mInsideDiscontinuousLoop = wasDiscontinuous;
+
+ return false;
+}
+
+bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill: outputTriplet(visit, "discard;\n", "", ""); break;
+ case EOpBreak:
+ if (visit == PreVisit)
+ {
+ if (mExcessiveLoopIndex)
+ {
+ out << "{Break";
+ mExcessiveLoopIndex->traverse(this);
+ out << " = true; break;}\n";
+ }
+ else
+ {
+ out << "break;\n";
+ }
+ }
+ break;
+ case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
+ case EOpReturn:
+ if (visit == PreVisit)
+ {
+ if (node->getExpression())
+ {
+ out << "return ";
+ }
+ else
+ {
+ out << "return;\n";
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ if (node->getExpression())
+ {
+ out << ";\n";
+ }
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+void OutputHLSL::traverseStatements(TIntermNode *node)
+{
+ if (isSingleStatement(node))
+ {
+ mUnfoldShortCircuit->traverse(node);
+ }
+
+ node->traverse(this);
+}
+
+bool OutputHLSL::isSingleStatement(TIntermNode *node)
+{
+ TIntermAggregate *aggregate = node->getAsAggregate();
+
+ if (aggregate)
+ {
+ if (aggregate->getOp() == EOpSequence)
+ {
+ return false;
+ }
+ else
+ {
+ for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
+ {
+ if (!isSingleStatement(*sit))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return true;
+}
+
+// Handle loops with more than 254 iterations (unsupported by D3D9) by splitting them
+// (The D3D documentation says 255 iterations, but the compiler complains at anything more than 254).
+bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
+{
+ const int MAX_LOOP_ITERATIONS = 254;
+ TInfoSinkBase &out = mBody;
+
+ // Parse loops of the form:
+ // for(int index = initial; index [comparator] limit; index += increment)
+ TIntermSymbol *index = NULL;
+ TOperator comparator = EOpNull;
+ int initial = 0;
+ int limit = 0;
+ int increment = 0;
+
+ // Parse index name and intial value
+ if (node->getInit())
+ {
+ TIntermAggregate *init = node->getInit()->getAsAggregate();
+
+ if (init)
+ {
+ TIntermSequence &sequence = init->getSequence();
+ TIntermTyped *variable = sequence[0]->getAsTyped();
+
+ if (variable && variable->getQualifier() == EvqTemporary)
+ {
+ TIntermBinary *assign = variable->getAsBinaryNode();
+
+ if (assign->getOp() == EOpInitialize)
+ {
+ TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
+ TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
+
+ if (symbol && constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+ {
+ index = symbol;
+ initial = constant->getIConst(0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Parse comparator and limit value
+ if (index != NULL && node->getCondition())
+ {
+ TIntermBinary *test = node->getCondition()->getAsBinaryNode();
+
+ if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
+ {
+ TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+ {
+ comparator = test->getOp();
+ limit = constant->getIConst(0);
+ }
+ }
+ }
+ }
+
+ // Parse increment
+ if (index != NULL && comparator != EOpNull && node->getExpression())
+ {
+ TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
+ TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
+
+ if (binaryTerminal)
+ {
+ TOperator op = binaryTerminal->getOp();
+ TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+ {
+ int value = constant->getIConst(0);
+
+ switch (op)
+ {
+ case EOpAddAssign: increment = value; break;
+ case EOpSubAssign: increment = -value; break;
+ default: UNIMPLEMENTED();
+ }
+ }
+ }
+ }
+ else if (unaryTerminal)
+ {
+ TOperator op = unaryTerminal->getOp();
+
+ switch (op)
+ {
+ case EOpPostIncrement: increment = 1; break;
+ case EOpPostDecrement: increment = -1; break;
+ case EOpPreIncrement: increment = 1; break;
+ case EOpPreDecrement: increment = -1; break;
+ default: UNIMPLEMENTED();
+ }
+ }
+ }
+
+ if (index != NULL && comparator != EOpNull && increment != 0)
+ {
+ if (comparator == EOpLessThanEqual)
+ {
+ comparator = EOpLessThan;
+ limit += 1;
+ }
+
+ if (comparator == EOpLessThan)
+ {
+ int iterations = (limit - initial) / increment;
+
+ if (iterations <= MAX_LOOP_ITERATIONS)
+ {
+ return false; // Not an excessive loop
+ }
+
+ TIntermSymbol *restoreIndex = mExcessiveLoopIndex;
+ mExcessiveLoopIndex = index;
+
+ out << "{int ";
+ index->traverse(this);
+ out << ";\n"
+ "bool Break";
+ index->traverse(this);
+ out << " = false;\n";
+
+ bool firstLoopFragment = true;
+
+ while (iterations > 0)
+ {
+ int clampedLimit = initial + increment * std::min(MAX_LOOP_ITERATIONS, iterations);
+
+ if (!firstLoopFragment)
+ {
+ out << "if(!Break";
+ index->traverse(this);
+ out << ") {\n";
+ }
+
+ if (iterations <= MAX_LOOP_ITERATIONS) // Last loop fragment
+ {
+ mExcessiveLoopIndex = NULL; // Stops setting the Break flag
+ }
+
+ // for(int index = initial; index < clampedLimit; index += increment)
+
+ out << "for(";
+ index->traverse(this);
+ out << " = ";
+ out << initial;
+
+ out << "; ";
+ index->traverse(this);
+ out << " < ";
+ out << clampedLimit;
+
+ out << "; ";
+ index->traverse(this);
+ out << " += ";
+ out << increment;
+ out << ")\n";
+
+ outputLineDirective(node->getLine().first_line);
+ out << "{\n";
+
+ if (node->getBody())
+ {
+ node->getBody()->traverse(this);
+ }
+
+ outputLineDirective(node->getLine().first_line);
+ out << ";}\n";
+
+ if (!firstLoopFragment)
+ {
+ out << "}\n";
+ }
+
+ firstLoopFragment = false;
+
+ initial += MAX_LOOP_ITERATIONS * increment;
+ iterations -= MAX_LOOP_ITERATIONS;
+ }
+
+ out << "}";
+
+ mExcessiveLoopIndex = restoreIndex;
+
+ return true;
+ }
+ else UNIMPLEMENTED();
+ }
+
+ return false; // Not handled as an excessive loop
+}
+
+void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (visit == PreVisit)
+ {
+ out << preString;
+ }
+ else if (visit == InVisit)
+ {
+ out << inString;
+ }
+ else if (visit == PostVisit)
+ {
+ out << postString;
+ }
+}
+
+void OutputHLSL::outputLineDirective(int line)
+{
+ if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
+ {
+ mBody << "\n";
+ mBody << "#line " << line;
+
+ if (mContext.sourcePath)
+ {
+ mBody << " \"" << mContext.sourcePath << "\"";
+ }
+
+ mBody << "\n";
+ }
+}
+
+TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
+{
+ TQualifier qualifier = symbol->getQualifier();
+ const TType &type = symbol->getType();
+ TString name = symbol->getSymbol();
+
+ if (name.empty()) // HLSL demands named arguments, also for prototypes
+ {
+ name = "x" + str(mUniqueIndex++);
+ }
+ else
+ {
+ name = decorate(name);
+ }
+
+ if (mOutputType == SH_HLSL11_OUTPUT && IsSampler(type.getBasicType()))
+ {
+ return qualifierString(qualifier) + " " + textureString(type) + " texture_" + name + arrayString(type) + ", " +
+ qualifierString(qualifier) + " SamplerState sampler_" + name + arrayString(type);
+ }
+
+ return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
+}
+
+TString OutputHLSL::qualifierString(TQualifier qualifier)
+{
+ switch(qualifier)
+ {
+ case EvqIn: return "in";
+ case EvqOut: return "out";
+ case EvqInOut: return "inout";
+ case EvqConstReadOnly: return "const";
+ default: UNREACHABLE();
+ }
+
+ return "";
+}
+
+TString OutputHLSL::typeString(const TType &type)
+{
+ if (type.getBasicType() == EbtStruct)
+ {
+ const TString& typeName = type.getStruct()->name();
+ if (typeName != "")
+ {
+ return structLookup(typeName);
+ }
+ else // Nameless structure, define in place
+ {
+ const TFieldList &fields = type.getStruct()->fields();
+
+ TString string = "struct\n"
+ "{\n";
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ const TField *field = fields[i];
+
+ string += " " + typeString(*field->type()) + " " + decorate(field->name()) + arrayString(*field->type()) + ";\n";
+ }
+
+ string += "} ";
+
+ return string;
+ }
+ }
+ else if (type.isMatrix())
+ {
+ switch (type.getNominalSize())
+ {
+ case 2: return "float2x2";
+ case 3: return "float3x3";
+ case 4: return "float4x4";
+ }
+ }
+ else
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ switch (type.getNominalSize())
+ {
+ case 1: return "float";
+ case 2: return "float2";
+ case 3: return "float3";
+ case 4: return "float4";
+ }
+ case EbtInt:
+ switch (type.getNominalSize())
+ {
+ case 1: return "int";
+ case 2: return "int2";
+ case 3: return "int3";
+ case 4: return "int4";
+ }
+ case EbtBool:
+ switch (type.getNominalSize())
+ {
+ case 1: return "bool";
+ case 2: return "bool2";
+ case 3: return "bool3";
+ case 4: return "bool4";
+ }
+ case EbtVoid:
+ return "void";
+ case EbtSampler2D:
+ return "sampler2D";
+ case EbtSamplerCube:
+ return "samplerCUBE";
+ case EbtSamplerExternalOES:
+ return "sampler2D";
+ default:
+ break;
+ }
+ }
+
+ UNREACHABLE();
+ return "<unknown type>";
+}
+
+TString OutputHLSL::textureString(const TType &type)
+{
+ switch (type.getBasicType())
+ {
+ case EbtSampler2D:
+ return "Texture2D";
+ case EbtSamplerCube:
+ return "TextureCube";
+ case EbtSamplerExternalOES:
+ return "Texture2D";
+ default:
+ break;
+ }
+
+ UNREACHABLE();
+ return "<unknown texture type>";
+}
+
+TString OutputHLSL::arrayString(const TType &type)
+{
+ if (!type.isArray())
+ {
+ return "";
+ }
+
+ return "[" + str(type.getArraySize()) + "]";
+}
+
+TString OutputHLSL::initializer(const TType &type)
+{
+ TString string;
+
+ size_t size = type.getObjectSize();
+ for (size_t component = 0; component < size; component++)
+ {
+ string += "0";
+
+ if (component + 1 < size)
+ {
+ string += ", ";
+ }
+ }
+
+ return "{" + string + "}";
+}
+
+void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
+{
+ if (name == "")
+ {
+ return; // Nameless structures don't have constructors
+ }
+
+ if (type.getStruct() && mStructNames.find(decorate(name)) != mStructNames.end())
+ {
+ return; // Already added
+ }
+
+ TType ctorType = type;
+ ctorType.clearArrayness();
+ ctorType.setPrecision(EbpHigh);
+ ctorType.setQualifier(EvqTemporary);
+
+ TString ctorName = type.getStruct() ? decorate(name) : name;
+
+ typedef std::vector<TType> ParameterArray;
+ ParameterArray ctorParameters;
+
+ if (type.getStruct())
+ {
+ mStructNames.insert(decorate(name));
+
+ TString structure;
+ structure += "struct " + decorate(name) + "\n"
+ "{\n";
+
+ const TFieldList &fields = type.getStruct()->fields();
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ const TField *field = fields[i];
+
+ structure += " " + typeString(*field->type()) + " " + decorateField(field->name(), type) + arrayString(*field->type()) + ";\n";
+ }
+
+ structure += "};\n";
+
+ if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
+ {
+ mStructDeclarations.push_back(structure);
+ }
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ ctorParameters.push_back(*fields[i]->type());
+ }
+ }
+ else if (parameters)
+ {
+ for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
+ {
+ ctorParameters.push_back((*parameter)->getAsTyped()->getType());
+ }
+ }
+ else UNREACHABLE();
+
+ TString constructor;
+
+ if (ctorType.getStruct())
+ {
+ constructor += ctorName + " " + ctorName + "_ctor(";
+ }
+ else // Built-in type
+ {
+ constructor += typeString(ctorType) + " " + ctorName + "(";
+ }
+
+ for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
+ {
+ const TType &type = ctorParameters[parameter];
+
+ constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
+
+ if (parameter < ctorParameters.size() - 1)
+ {
+ constructor += ", ";
+ }
+ }
+
+ constructor += ")\n"
+ "{\n";
+
+ if (ctorType.getStruct())
+ {
+ constructor += " " + ctorName + " structure = {";
+ }
+ else
+ {
+ constructor += " return " + typeString(ctorType) + "(";
+ }
+
+ if (ctorType.isMatrix() && ctorParameters.size() == 1)
+ {
+ int dim = ctorType.getNominalSize();
+ const TType &parameter = ctorParameters[0];
+
+ if (parameter.isScalar())
+ {
+ for (int row = 0; row < dim; row++)
+ {
+ for (int col = 0; col < dim; col++)
+ {
+ constructor += TString((row == col) ? "x0" : "0.0");
+
+ if (row < dim - 1 || col < dim - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else if (parameter.isMatrix())
+ {
+ for (int row = 0; row < dim; row++)
+ {
+ for (int col = 0; col < dim; col++)
+ {
+ if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
+ {
+ constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
+ }
+ else
+ {
+ constructor += TString((row == col) ? "1.0" : "0.0");
+ }
+
+ if (row < dim - 1 || col < dim - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else UNREACHABLE();
+ }
+ else
+ {
+ size_t remainingComponents = ctorType.getObjectSize();
+ size_t parameterIndex = 0;
+
+ while (remainingComponents > 0)
+ {
+ const TType &parameter = ctorParameters[parameterIndex];
+ const size_t parameterSize = parameter.getObjectSize();
+ bool moreParameters = parameterIndex + 1 < ctorParameters.size();
+
+ constructor += "x" + str(parameterIndex);
+
+ if (parameter.isScalar())
+ {
+ ASSERT(parameterSize <= remainingComponents);
+ remainingComponents -= parameterSize;
+ }
+ else if (parameter.isVector())
+ {
+ if (remainingComponents == parameterSize || moreParameters)
+ {
+ ASSERT(parameterSize <= remainingComponents);
+ remainingComponents -= parameterSize;
+ }
+ else if (remainingComponents < static_cast<size_t>(parameter.getNominalSize()))
+ {
+ switch (remainingComponents)
+ {
+ case 1: constructor += ".x"; break;
+ case 2: constructor += ".xy"; break;
+ case 3: constructor += ".xyz"; break;
+ case 4: constructor += ".xyzw"; break;
+ default: UNREACHABLE();
+ }
+
+ remainingComponents = 0;
+ }
+ else UNREACHABLE();
+ }
+ else if (parameter.isMatrix() || parameter.getStruct())
+ {
+ ASSERT(remainingComponents == parameterSize || moreParameters);
+ ASSERT(parameterSize <= remainingComponents);
+
+ remainingComponents -= parameterSize;
+ }
+ else UNREACHABLE();
+
+ if (moreParameters)
+ {
+ parameterIndex++;
+ }
+
+ if (remainingComponents)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+
+ if (ctorType.getStruct())
+ {
+ constructor += "};\n"
+ " return structure;\n"
+ "}\n";
+ }
+ else
+ {
+ constructor += ");\n"
+ "}\n";
+ }
+
+ mConstructors.insert(constructor);
+}
+
+const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ out << structLookup(type.getStruct()->name()) + "_ctor(";
+
+ const TFieldList &fields = type.getStruct()->fields();
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ const TType *fieldType = fields[i]->type();
+
+ constUnion = writeConstantUnion(*fieldType, constUnion);
+
+ if (i != fields.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")";
+ }
+ else
+ {
+ size_t size = type.getObjectSize();
+ bool writeType = size > 1;
+
+ if (writeType)
+ {
+ out << typeString(type) << "(";
+ }
+
+ for (size_t i = 0; i < size; i++, constUnion++)
+ {
+ switch (constUnion->getType())
+ {
+ case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, constUnion->getFConst())); break;
+ case EbtInt: out << constUnion->getIConst(); break;
+ case EbtBool: out << constUnion->getBConst(); break;
+ default: UNREACHABLE();
+ }
+
+ if (i != size - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ if (writeType)
+ {
+ out << ")";
+ }
+ }
+
+ return constUnion;
+}
+
+TString OutputHLSL::scopeString(unsigned int depthLimit)
+{
+ TString string;
+
+ for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
+ {
+ string += "_" + str(i);
+ }
+
+ return string;
+}
+
+TString OutputHLSL::scopedStruct(const TString &typeName)
+{
+ if (typeName == "")
+ {
+ return typeName;
+ }
+
+ return typeName + scopeString(mScopeDepth);
+}
+
+TString OutputHLSL::structLookup(const TString &typeName)
+{
+ for (int depth = mScopeDepth; depth >= 0; depth--)
+ {
+ TString scopedName = decorate(typeName + scopeString(depth));
+
+ for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
+ {
+ if (*structName == scopedName)
+ {
+ return scopedName;
+ }
+ }
+ }
+
+ UNREACHABLE(); // Should have found a matching constructor
+
+ return typeName;
+}
+
+TString OutputHLSL::decorate(const TString &string)
+{
+ if (string.compare(0, 3, "gl_") != 0 && string.compare(0, 3, "dx_") != 0)
+ {
+ return "_" + string;
+ }
+
+ return string;
+}
+
+TString OutputHLSL::decorateUniform(const TString &string, const TType &type)
+{
+ if (type.getBasicType() == EbtSamplerExternalOES)
+ {
+ return "ex_" + string;
+ }
+
+ return decorate(string);
+}
+
+TString OutputHLSL::decorateField(const TString &string, const TType &structure)
+{
+ if (structure.getStruct()->name().compare(0, 3, "gl_") != 0)
+ {
+ return decorate(string);
+ }
+
+ return string;
+}
+
+TString OutputHLSL::registerString(TIntermSymbol *operand)
+{
+ ASSERT(operand->getQualifier() == EvqUniform);
+
+ if (IsSampler(operand->getBasicType()))
+ {
+ return "s" + str(samplerRegister(operand));
+ }
+
+ return "c" + str(uniformRegister(operand));
+}
+
+int OutputHLSL::samplerRegister(TIntermSymbol *sampler)
+{
+ const TType &type = sampler->getType();
+ ASSERT(IsSampler(type.getBasicType()));
+
+ int index = mSamplerRegister;
+ mSamplerRegister += sampler->totalRegisterCount();
+
+ declareUniform(type, sampler->getSymbol(), index);
+
+ return index;
+}
+
+int OutputHLSL::uniformRegister(TIntermSymbol *uniform)
+{
+ const TType &type = uniform->getType();
+ ASSERT(!IsSampler(type.getBasicType()));
+
+ int index = mUniformRegister;
+ mUniformRegister += uniform->totalRegisterCount();
+
+ declareUniform(type, uniform->getSymbol(), index);
+
+ return index;
+}
+
+void OutputHLSL::declareUniform(const TType &type, const TString &name, int index)
+{
+ TStructure *structure = type.getStruct();
+
+ if (!structure)
+ {
+ mActiveUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), index));
+ }
+ else
+ {
+ const TFieldList &fields = structure->fields();
+
+ if (type.isArray())
+ {
+ int elementIndex = index;
+
+ for (int i = 0; i < type.getArraySize(); i++)
+ {
+ for (size_t j = 0; j < fields.size(); j++)
+ {
+ const TType &fieldType = *fields[j]->type();
+ const TString uniformName = name + "[" + str(i) + "]." + fields[j]->name();
+ declareUniform(fieldType, uniformName, elementIndex);
+ elementIndex += fieldType.totalRegisterCount();
+ }
+ }
+ }
+ else
+ {
+ int fieldIndex = index;
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ const TType &fieldType = *fields[i]->type();
+ const TString uniformName = name + "." + fields[i]->name();
+ declareUniform(fieldType, uniformName, fieldIndex);
+ fieldIndex += fieldType.totalRegisterCount();
+ }
+ }
+ }
+}
+
+GLenum OutputHLSL::glVariableType(const TType &type)
+{
+ if (type.getBasicType() == EbtFloat)
+ {
+ if (type.isScalar())
+ {
+ return GL_FLOAT;
+ }
+ else if (type.isVector())
+ {
+ switch(type.getNominalSize())
+ {
+ case 2: return GL_FLOAT_VEC2;
+ case 3: return GL_FLOAT_VEC3;
+ case 4: return GL_FLOAT_VEC4;
+ default: UNREACHABLE();
+ }
+ }
+ else if (type.isMatrix())
+ {
+ switch(type.getNominalSize())
+ {
+ case 2: return GL_FLOAT_MAT2;
+ case 3: return GL_FLOAT_MAT3;
+ case 4: return GL_FLOAT_MAT4;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ else if (type.getBasicType() == EbtInt)
+ {
+ if (type.isScalar())
+ {
+ return GL_INT;
+ }
+ else if (type.isVector())
+ {
+ switch(type.getNominalSize())
+ {
+ case 2: return GL_INT_VEC2;
+ case 3: return GL_INT_VEC3;
+ case 4: return GL_INT_VEC4;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ else if (type.getBasicType() == EbtBool)
+ {
+ if (type.isScalar())
+ {
+ return GL_BOOL;
+ }
+ else if (type.isVector())
+ {
+ switch(type.getNominalSize())
+ {
+ case 2: return GL_BOOL_VEC2;
+ case 3: return GL_BOOL_VEC3;
+ case 4: return GL_BOOL_VEC4;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ else if (type.getBasicType() == EbtSampler2D)
+ {
+ return GL_SAMPLER_2D;
+ }
+ else if (type.getBasicType() == EbtSamplerCube)
+ {
+ return GL_SAMPLER_CUBE;
+ }
+ else UNREACHABLE();
+
+ return GL_NONE;
+}
+
+GLenum OutputHLSL::glVariablePrecision(const TType &type)
+{
+ if (type.getBasicType() == EbtFloat)
+ {
+ switch (type.getPrecision())
+ {
+ case EbpHigh: return GL_HIGH_FLOAT;
+ case EbpMedium: return GL_MEDIUM_FLOAT;
+ case EbpLow: return GL_LOW_FLOAT;
+ case EbpUndefined:
+ // Should be defined as the default precision by the parser
+ default: UNREACHABLE();
+ }
+ }
+ else if (type.getBasicType() == EbtInt)
+ {
+ switch (type.getPrecision())
+ {
+ case EbpHigh: return GL_HIGH_INT;
+ case EbpMedium: return GL_MEDIUM_INT;
+ case EbpLow: return GL_LOW_INT;
+ case EbpUndefined:
+ // Should be defined as the default precision by the parser
+ default: UNREACHABLE();
+ }
+ }
+
+ // Other types (boolean, sampler) don't have a precision
+ return GL_NONE;
+}
+
+}
diff --git a/src/compiler/OutputHLSL.h b/src/compiler/OutputHLSL.h
new file mode 100644
index 00000000..cde41207
--- /dev/null
+++ b/src/compiler/OutputHLSL.h
@@ -0,0 +1,166 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_OUTPUTHLSL_H_
+#define COMPILER_OUTPUTHLSL_H_
+
+#include <list>
+#include <set>
+#include <map>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/Uniform.h"
+
+namespace sh
+{
+class UnfoldShortCircuit;
+
+class OutputHLSL : public TIntermTraverser
+{
+ public:
+ OutputHLSL(TParseContext &context, const ShBuiltInResources& resources, ShShaderOutput outputType);
+ ~OutputHLSL();
+
+ void output();
+
+ TInfoSinkBase &getBodyStream();
+ const ActiveUniforms &getUniforms();
+
+ TString typeString(const TType &type);
+ TString textureString(const TType &type);
+ static TString qualifierString(TQualifier qualifier);
+ static TString arrayString(const TType &type);
+ static TString initializer(const TType &type);
+ static TString decorate(const TString &string); // Prepends an underscore to avoid naming clashes
+ static TString decorateUniform(const TString &string, const TType &type);
+ static TString decorateField(const TString &string, const TType &structure);
+
+ protected:
+ void header();
+
+ // Visit AST nodes and output their code to the body stream
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+
+ void traverseStatements(TIntermNode *node);
+ bool isSingleStatement(TIntermNode *node);
+ bool handleExcessiveLoop(TIntermLoop *node);
+ void outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString);
+ void outputLineDirective(int line);
+ TString argumentString(const TIntermSymbol *symbol);
+ int vectorSize(const TType &type) const;
+
+ void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters);
+ const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
+
+ TString scopeString(unsigned int depthLimit);
+ TString scopedStruct(const TString &typeName);
+ TString structLookup(const TString &typeName);
+
+ TParseContext &mContext;
+ const ShShaderOutput mOutputType;
+ UnfoldShortCircuit *mUnfoldShortCircuit;
+ bool mInsideFunction;
+
+ // Output streams
+ TInfoSinkBase mHeader;
+ TInfoSinkBase mBody;
+ TInfoSinkBase mFooter;
+
+ typedef std::map<TString, TIntermSymbol*> ReferencedSymbols;
+ ReferencedSymbols mReferencedUniforms;
+ ReferencedSymbols mReferencedAttributes;
+ ReferencedSymbols mReferencedVaryings;
+
+ // Parameters determining what goes in the header output
+ bool mUsesTexture2D;
+ bool mUsesTexture2D_bias;
+ bool mUsesTexture2DLod;
+ bool mUsesTexture2DProj;
+ bool mUsesTexture2DProj_bias;
+ bool mUsesTexture2DProjLod;
+ bool mUsesTextureCube;
+ bool mUsesTextureCube_bias;
+ bool mUsesTextureCubeLod;
+ bool mUsesTexture2DLod0;
+ bool mUsesTexture2DLod0_bias;
+ bool mUsesTexture2DProjLod0;
+ bool mUsesTexture2DProjLod0_bias;
+ bool mUsesTextureCubeLod0;
+ bool mUsesTextureCubeLod0_bias;
+ bool mUsesFragColor;
+ bool mUsesFragData;
+ bool mUsesDepthRange;
+ bool mUsesFragCoord;
+ bool mUsesPointCoord;
+ bool mUsesFrontFacing;
+ bool mUsesPointSize;
+ bool mUsesFragDepth;
+ bool mUsesXor;
+ bool mUsesMod1;
+ bool mUsesMod2v;
+ bool mUsesMod2f;
+ bool mUsesMod3v;
+ bool mUsesMod3f;
+ bool mUsesMod4v;
+ bool mUsesMod4f;
+ bool mUsesFaceforward1;
+ bool mUsesFaceforward2;
+ bool mUsesFaceforward3;
+ bool mUsesFaceforward4;
+ bool mUsesAtan2_1;
+ bool mUsesAtan2_2;
+ bool mUsesAtan2_3;
+ bool mUsesAtan2_4;
+
+ int mNumRenderTargets;
+
+ typedef std::set<TString> Constructors;
+ Constructors mConstructors;
+
+ typedef std::set<TString> StructNames;
+ StructNames mStructNames;
+
+ typedef std::list<TString> StructDeclarations;
+ StructDeclarations mStructDeclarations;
+
+ typedef std::vector<int> ScopeBracket;
+ ScopeBracket mScopeBracket;
+ unsigned int mScopeDepth;
+
+ int mUniqueIndex; // For creating unique names
+
+ bool mContainsLoopDiscontinuity;
+ bool mOutputLod0Function;
+ bool mInsideDiscontinuousLoop;
+
+ TIntermSymbol *mExcessiveLoopIndex;
+
+ int mUniformRegister;
+ int mSamplerRegister;
+
+ TString registerString(TIntermSymbol *operand);
+ int samplerRegister(TIntermSymbol *sampler);
+ int uniformRegister(TIntermSymbol *uniform);
+ void declareUniform(const TType &type, const TString &name, int index);
+ static GLenum glVariableType(const TType &type);
+ static GLenum glVariablePrecision(const TType &type);
+
+ ActiveUniforms mActiveUniforms;
+};
+}
+
+#endif // COMPILER_OUTPUTHLSL_H_
diff --git a/src/compiler/ParseHelper.cpp b/src/compiler/ParseHelper.cpp
new file mode 100644
index 00000000..a4787a1c
--- /dev/null
+++ b/src/compiler/ParseHelper.cpp
@@ -0,0 +1,1600 @@
+//
+// 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.
+//
+
+#include "compiler/ParseHelper.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "compiler/glslang.h"
+#include "compiler/preprocessor/SourceLocation.h"
+
+///////////////////////////////////////////////////////////////////////
+//
+// Sub- vector and matrix fields
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Look at a '.' field selector string and change it into offsets
+// for a vector.
+//
+bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, const TSourceLoc& line)
+{
+ fields.num = (int) compString.size();
+ if (fields.num > 4) {
+ error(line, "illegal vector field selection", compString.c_str());
+ return false;
+ }
+
+ enum {
+ exyzw,
+ ergba,
+ estpq
+ } fieldSet[4];
+
+ for (int i = 0; i < fields.num; ++i) {
+ switch (compString[i]) {
+ case 'x':
+ fields.offsets[i] = 0;
+ fieldSet[i] = exyzw;
+ break;
+ case 'r':
+ fields.offsets[i] = 0;
+ fieldSet[i] = ergba;
+ break;
+ case 's':
+ fields.offsets[i] = 0;
+ fieldSet[i] = estpq;
+ break;
+ case 'y':
+ fields.offsets[i] = 1;
+ fieldSet[i] = exyzw;
+ break;
+ case 'g':
+ fields.offsets[i] = 1;
+ fieldSet[i] = ergba;
+ break;
+ case 't':
+ fields.offsets[i] = 1;
+ fieldSet[i] = estpq;
+ break;
+ case 'z':
+ fields.offsets[i] = 2;
+ fieldSet[i] = exyzw;
+ break;
+ case 'b':
+ fields.offsets[i] = 2;
+ fieldSet[i] = ergba;
+ break;
+ case 'p':
+ fields.offsets[i] = 2;
+ fieldSet[i] = estpq;
+ break;
+
+ case 'w':
+ fields.offsets[i] = 3;
+ fieldSet[i] = exyzw;
+ break;
+ case 'a':
+ fields.offsets[i] = 3;
+ fieldSet[i] = ergba;
+ break;
+ case 'q':
+ fields.offsets[i] = 3;
+ fieldSet[i] = estpq;
+ break;
+ default:
+ error(line, "illegal vector field selection", compString.c_str());
+ return false;
+ }
+ }
+
+ for (int i = 0; i < fields.num; ++i) {
+ if (fields.offsets[i] >= vecSize) {
+ error(line, "vector field selection out of range", compString.c_str());
+ return false;
+ }
+
+ if (i > 0) {
+ if (fieldSet[i] != fieldSet[i-1]) {
+ error(line, "illegal - vector component fields not from the same set", compString.c_str());
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+//
+// Look at a '.' field selector string and change it into offsets
+// for a matrix.
+//
+bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, const TSourceLoc& line)
+{
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = -1;
+ fields.col = -1;
+
+ if (compString.size() != 2) {
+ error(line, "illegal length of matrix field selection", compString.c_str());
+ return false;
+ }
+
+ if (compString[0] == '_') {
+ if (compString[1] < '0' || compString[1] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str());
+ return false;
+ }
+ fields.wholeCol = true;
+ fields.col = compString[1] - '0';
+ } else if (compString[1] == '_') {
+ if (compString[0] < '0' || compString[0] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str());
+ return false;
+ }
+ fields.wholeRow = true;
+ fields.row = compString[0] - '0';
+ } else {
+ if (compString[0] < '0' || compString[0] > '3' ||
+ compString[1] < '0' || compString[1] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str());
+ return false;
+ }
+ fields.row = compString[0] - '0';
+ fields.col = compString[1] - '0';
+ }
+
+ if (fields.row >= matSize || fields.col >= matSize) {
+ error(line, "matrix field selection out of range", compString.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Errors
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Track whether errors have occurred.
+//
+void TParseContext::recover()
+{
+}
+
+//
+// Used by flex/bison to output all syntax and parsing errors.
+//
+void TParseContext::error(const TSourceLoc& loc,
+ const char* reason, const char* token,
+ const char* extraInfo)
+{
+ pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ diagnostics.writeInfo(pp::Diagnostics::ERROR,
+ srcLoc, reason, token, extraInfo);
+
+}
+
+void TParseContext::warning(const TSourceLoc& loc,
+ const char* reason, const char* token,
+ const char* extraInfo) {
+ pp::SourceLocation srcLoc;
+ srcLoc.file = loc.first_file;
+ srcLoc.line = loc.first_line;
+ diagnostics.writeInfo(pp::Diagnostics::WARNING,
+ srcLoc, reason, token, extraInfo);
+}
+
+void TParseContext::trace(const char* str)
+{
+ diagnostics.writeDebug(str);
+}
+
+//
+// Same error message for all places assignments don't work.
+//
+void TParseContext::assignError(const TSourceLoc& line, const char* op, TString left, TString right)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "cannot convert from '" << right << "' to '" << left << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", op, extraInfo.c_str());
+}
+
+//
+// Same error message for all places unary operations don't work.
+//
+void TParseContext::unaryOpError(const TSourceLoc& line, const char* op, TString operand)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "no operation '" << op << "' exists that takes an operand of type " << operand
+ << " (or there is no acceptable conversion)";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " wrong operand type", op, extraInfo.c_str());
+}
+
+//
+// Same error message for all binary operations don't work.
+//
+void TParseContext::binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right)
+{
+ std::stringstream extraInfoStream;
+ extraInfoStream << "no operation '" << op << "' exists that takes a left-hand operand of type '" << left
+ << "' and a right operand of type '" << right << "' (or there is no acceptable conversion)";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " wrong operand types ", op, extraInfo.c_str());
+}
+
+bool TParseContext::precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type){
+ if (!checksPrecisionErrors)
+ return false;
+ switch( type ){
+ case EbtFloat:
+ if( precision == EbpUndefined ){
+ error( line, "No precision specified for (float)", "" );
+ return true;
+ }
+ break;
+ case EbtInt:
+ if( precision == EbpUndefined ){
+ error( line, "No precision specified (int)", "" );
+ return true;
+ }
+ break;
+ default:
+ return false;
+ }
+ return false;
+}
+
+//
+// Both test and if necessary, spit out an error, to see if the node is really
+// an l-value that can be operated on this way.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped* node)
+{
+ TIntermSymbol* symNode = node->getAsSymbolNode();
+ TIntermBinary* binaryNode = node->getAsBinaryNode();
+
+ if (binaryNode) {
+ bool errorReturn;
+
+ switch(binaryNode->getOp()) {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectStruct:
+ return lValueErrorCheck(line, op, binaryNode->getLeft());
+ case EOpVectorSwizzle:
+ errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
+ if (!errorReturn) {
+ int offset[4] = {0,0,0,0};
+
+ TIntermTyped* rightNode = binaryNode->getRight();
+ TIntermAggregate *aggrNode = rightNode->getAsAggregate();
+
+ for (TIntermSequence::iterator p = aggrNode->getSequence().begin();
+ p != aggrNode->getSequence().end(); p++) {
+ int value = (*p)->getAsTyped()->getAsConstantUnion()->getIConst(0);
+ offset[value]++;
+ if (offset[value] > 1) {
+ error(line, " l-value of swizzle cannot have duplicate components", op);
+
+ return true;
+ }
+ }
+ }
+
+ return errorReturn;
+ default:
+ break;
+ }
+ error(line, " l-value required", op);
+
+ return true;
+ }
+
+
+ const char* symbol = 0;
+ if (symNode != 0)
+ symbol = symNode->getSymbol().c_str();
+
+ const char* message = 0;
+ switch (node->getQualifier()) {
+ case EvqConst: message = "can't modify a const"; break;
+ case EvqConstReadOnly: message = "can't modify a const"; break;
+ case EvqAttribute: message = "can't modify an attribute"; break;
+ case EvqUniform: message = "can't modify a uniform"; break;
+ case EvqVaryingIn: message = "can't modify a varying"; break;
+ case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
+ case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break;
+ case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
+ default:
+
+ //
+ // Type that can't be written to?
+ //
+ switch (node->getBasicType()) {
+ case EbtSampler2D:
+ case EbtSamplerCube:
+ message = "can't modify a sampler";
+ break;
+ case EbtVoid:
+ message = "can't modify void";
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (message == 0 && binaryNode == 0 && symNode == 0) {
+ error(line, " l-value required", op);
+
+ return true;
+ }
+
+
+ //
+ // Everything else is okay, no error.
+ //
+ if (message == 0)
+ return false;
+
+ //
+ // If we get here, we have an error and a message.
+ //
+ if (symNode) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "\"" << symbol << "\" (" << message << ")";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " l-value required", op, extraInfo.c_str());
+ }
+ else {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "(" << message << ")";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " l-value required", op, extraInfo.c_str());
+ }
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// a constant.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::constErrorCheck(TIntermTyped* node)
+{
+ if (node->getQualifier() == EvqConst)
+ return false;
+
+ error(node->getLine(), "constant expression required", "");
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// an integer.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
+{
+ if (node->getBasicType() == EbtInt && node->getNominalSize() == 1)
+ return false;
+
+ error(node->getLine(), "integer expression required", token);
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if we are currently
+// globally scoped.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::globalErrorCheck(const TSourceLoc& line, bool global, const char* token)
+{
+ if (global)
+ return false;
+
+ error(line, "only allowed at global scope", token);
+
+ return true;
+}
+
+//
+// For now, keep it simple: if it starts "gl_", it's reserved, independent
+// of scope. Except, if the symbol table is at the built-in push-level,
+// which is when we are parsing built-ins.
+// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
+// webgl shader.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::reservedErrorCheck(const TSourceLoc& line, const TString& identifier)
+{
+ static const char* reservedErrMsg = "reserved built-in name";
+ if (!symbolTable.atBuiltInLevel()) {
+ if (identifier.compare(0, 3, "gl_") == 0) {
+ error(line, reservedErrMsg, "gl_");
+ return true;
+ }
+ if (isWebGLBasedSpec(shaderSpec)) {
+ if (identifier.compare(0, 6, "webgl_") == 0) {
+ error(line, reservedErrMsg, "webgl_");
+ return true;
+ }
+ if (identifier.compare(0, 7, "_webgl_") == 0) {
+ error(line, reservedErrMsg, "_webgl_");
+ return true;
+ }
+ if (shaderSpec == SH_CSS_SHADERS_SPEC && identifier.compare(0, 4, "css_") == 0) {
+ error(line, reservedErrMsg, "css_");
+ return true;
+ }
+ }
+ if (identifier.find("__") != TString::npos) {
+ error(line, "identifiers containing two consecutive underscores (__) are reserved as possible future keywords", identifier.c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Make sure there is enough data provided to the constructor to build
+// something of the type of the constructor. Also returns the type of
+// the constructor.
+//
+// Returns true if there was an error in construction.
+//
+bool TParseContext::constructorErrorCheck(const TSourceLoc& line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
+{
+ *type = function.getReturnType();
+
+ bool constructingMatrix = false;
+ switch(op) {
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ constructingMatrix = true;
+ break;
+ default:
+ break;
+ }
+
+ //
+ // Note: It's okay to have too many components available, but not okay to have unused
+ // arguments. 'full' will go to true when enough args have been seen. If we loop
+ // again, there is an extra argument, so 'overfull' will become true.
+ //
+
+ size_t size = 0;
+ bool constType = true;
+ bool full = false;
+ bool overFull = false;
+ bool matrixInMatrix = false;
+ bool arrayArg = false;
+ for (size_t i = 0; i < function.getParamCount(); ++i) {
+ const TParameter& param = function.getParam(i);
+ size += param.type->getObjectSize();
+
+ if (constructingMatrix && param.type->isMatrix())
+ matrixInMatrix = true;
+ if (full)
+ overFull = true;
+ if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
+ full = true;
+ if (param.type->getQualifier() != EvqConst)
+ constType = false;
+ if (param.type->isArray())
+ arrayArg = true;
+ }
+
+ if (constType)
+ type->setQualifier(EvqConst);
+
+ if (type->isArray() && static_cast<size_t>(type->getArraySize()) != function.getParamCount()) {
+ error(line, "array constructor needs one argument per array element", "constructor");
+ return true;
+ }
+
+ if (arrayArg && op != EOpConstructStruct) {
+ error(line, "constructing from a non-dereferenced array", "constructor");
+ return true;
+ }
+
+ if (matrixInMatrix && !type->isArray()) {
+ if (function.getParamCount() != 1) {
+ error(line, "constructing matrix from matrix can only take one argument", "constructor");
+ return true;
+ }
+ }
+
+ if (overFull) {
+ error(line, "too many arguments", "constructor");
+ return true;
+ }
+
+ if (op == EOpConstructStruct && !type->isArray() && int(type->getStruct()->fields().size()) != function.getParamCount()) {
+ error(line, "Number of constructor parameters does not match the number of structure fields", "constructor");
+ return true;
+ }
+
+ if (!type->isMatrix() || !matrixInMatrix) {
+ if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
+ (op == EOpConstructStruct && size < type->getObjectSize())) {
+ error(line, "not enough data provided for construction", "constructor");
+ return true;
+ }
+ }
+
+ TIntermTyped *typed = node ? node->getAsTyped() : 0;
+ if (typed == 0) {
+ error(line, "constructor argument does not have a type", "constructor");
+ return true;
+ }
+ if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
+ error(line, "cannot convert a sampler", "constructor");
+ return true;
+ }
+ if (typed->getBasicType() == EbtVoid) {
+ error(line, "cannot convert a void", "constructor");
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if a void variable has been declared and raise an error message for such a case
+//
+// returns true in case of an error
+//
+bool TParseContext::voidErrorCheck(const TSourceLoc& line, const TString& identifier, const TPublicType& pubType)
+{
+ if (pubType.type == EbtVoid) {
+ error(line, "illegal use of type 'void'", identifier.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+//
+// returns true in case of an error
+//
+bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TIntermTyped* type)
+{
+ if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
+ error(line, "boolean expression expected", "");
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+//
+// returns true in case of an error
+//
+bool TParseContext::boolErrorCheck(const TSourceLoc& line, const TPublicType& pType)
+{
+ if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) {
+ error(line, "boolean expression expected", "");
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason)
+{
+ if (pType.type == EbtStruct) {
+ if (containsSampler(*pType.userDef)) {
+ error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
+
+ return true;
+ }
+
+ return false;
+ } else if (IsSampler(pType.type)) {
+ error(line, reason, getBasicString(pType.type));
+
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType)
+{
+ if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) &&
+ pType.type == EbtStruct) {
+ error(line, "cannot be used with a structure", getQualifierString(pType.qualifier));
+
+ return true;
+ }
+
+ if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type)
+{
+ if ((qualifier == EvqOut || qualifier == EvqInOut) &&
+ type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
+ error(line, "samplers cannot be output parameters", type.getBasicString());
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::containsSampler(TType& type)
+{
+ if (IsSampler(type.getBasicType()))
+ return true;
+
+ if (type.getBasicType() == EbtStruct) {
+ const TFieldList& fields = type.getStruct()->fields();
+ for (unsigned int i = 0; i < fields.size(); ++i) {
+ if (containsSampler(*fields[i]->type()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Do size checking for an array type's size.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size)
+{
+ TIntermConstantUnion* constant = expr->getAsConstantUnion();
+ if (constant == 0 || constant->getBasicType() != EbtInt) {
+ error(line, "array size must be a constant integer expression", "");
+ return true;
+ }
+
+ size = constant->getIConst(0);
+
+ if (size <= 0) {
+ error(line, "array size must be a positive integer", "");
+ size = 1;
+ return true;
+ }
+
+ return false;
+}
+
+//
+// See if this qualifier can be an array.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type)
+{
+ if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConst)) {
+ error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str());
+ return true;
+ }
+
+ return false;
+}
+
+//
+// See if this type can be an array.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type)
+{
+ //
+ // Can the type be an array?
+ //
+ if (type.array) {
+ error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str());
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Do all the semantic checking for declaring an array, with and
+// without a size, and make the right changes to the symbol table.
+//
+// size == 0 means no specified size.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::arrayErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType type, TVariable*& variable)
+{
+ //
+ // Don't check for reserved word use until after we know it's not in the symbol table,
+ // because reserved arrays can be redeclared.
+ //
+
+ bool builtIn = false;
+ bool sameScope = false;
+ TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope);
+ if (symbol == 0 || !sameScope) {
+ if (reservedErrorCheck(line, identifier))
+ return true;
+
+ variable = new TVariable(&identifier, TType(type));
+
+ if (type.arraySize)
+ variable->getType().setArraySize(type.arraySize);
+
+ if (! symbolTable.insert(*variable)) {
+ delete variable;
+ error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str());
+ return true;
+ }
+ } else {
+ if (! symbol->isVariable()) {
+ error(line, "variable expected", identifier.c_str());
+ return true;
+ }
+
+ variable = static_cast<TVariable*>(symbol);
+ if (! variable->getType().isArray()) {
+ error(line, "redeclaring non-array as array", identifier.c_str());
+ return true;
+ }
+ if (variable->getType().getArraySize() > 0) {
+ error(line, "redeclaration of array with size", identifier.c_str());
+ return true;
+ }
+
+ if (! variable->getType().sameElementType(TType(type))) {
+ error(line, "redeclaration of array with a different type", identifier.c_str());
+ return true;
+ }
+
+ if (type.arraySize)
+ variable->getType().setArraySize(type.arraySize);
+ }
+
+ if (voidErrorCheck(line, identifier, type))
+ return true;
+
+ return false;
+}
+
+//
+// Enforce non-initializer type/qualifier rules.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::nonInitConstErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, bool array)
+{
+ if (type.qualifier == EvqConst)
+ {
+ // Make the qualifier make sense.
+ type.qualifier = EvqTemporary;
+
+ if (array)
+ {
+ error(line, "arrays may not be declared constant since they cannot be initialized", identifier.c_str());
+ }
+ else if (type.isStructureContainingArrays())
+ {
+ error(line, "structures containing arrays may not be declared constant since they cannot be initialized", identifier.c_str());
+ }
+ else
+ {
+ error(line, "variables with qualifier 'const' must be initialized", identifier.c_str());
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Do semantic checking for a variable declaration that has no initializer,
+// and update the symbol table.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::nonInitErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, TVariable*& variable)
+{
+ if (reservedErrorCheck(line, identifier))
+ recover();
+
+ variable = new TVariable(&identifier, TType(type));
+
+ if (! symbolTable.insert(*variable)) {
+ error(line, "redefinition", variable->getName().c_str());
+ delete variable;
+ variable = 0;
+ return true;
+ }
+
+ if (voidErrorCheck(line, identifier, type))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
+{
+ if (qualifier != EvqConst && qualifier != EvqTemporary) {
+ error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier));
+ return true;
+ }
+ if (qualifier == EvqConst && paramQualifier != EvqIn) {
+ error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
+ return true;
+ }
+
+ if (qualifier == EvqConst)
+ type->setQualifier(EvqConstReadOnly);
+ else
+ type->setQualifier(paramQualifier);
+
+ return false;
+}
+
+bool TParseContext::extensionErrorCheck(const TSourceLoc& line, const TString& extension)
+{
+ const TExtensionBehavior& extBehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extBehavior.find(extension.c_str());
+ if (iter == extBehavior.end()) {
+ error(line, "extension", extension.c_str(), "is not supported");
+ return true;
+ }
+ // In GLSL ES, an extension's default behavior is "disable".
+ if (iter->second == EBhDisable || iter->second == EBhUndefined) {
+ error(line, "extension", extension.c_str(), "is disabled");
+ return true;
+ }
+ if (iter->second == EBhWarn) {
+ warning(line, "extension", extension.c_str(), "is being used");
+ return false;
+ }
+
+ return false;
+}
+
+bool TParseContext::supportsExtension(const char* extension)
+{
+ const TExtensionBehavior& extbehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
+ return (iter != extbehavior.end());
+}
+
+bool TParseContext::isExtensionEnabled(const char* extension) const
+{
+ const TExtensionBehavior& extbehavior = extensionBehavior();
+ TExtensionBehavior::const_iterator iter = extbehavior.find(extension);
+
+ if (iter == extbehavior.end())
+ {
+ return false;
+ }
+
+ return (iter->second == EBhEnable || iter->second == EBhRequire);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Non-Errors.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+//
+// Look up a function name in the symbol table, and make sure it is a function.
+//
+// Return the function symbol if found, otherwise 0.
+//
+const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, bool *builtIn)
+{
+ // First find by unmangled name to check whether the function name has been
+ // hidden by a variable name or struct typename.
+ // If a function is found, check for one with a matching argument list.
+ const TSymbol* symbol = symbolTable.find(call->getName(), builtIn);
+ if (symbol == 0 || symbol->isFunction()) {
+ symbol = symbolTable.find(call->getMangledName(), builtIn);
+ }
+
+ if (symbol == 0) {
+ error(line, "no matching overloaded function found", call->getName().c_str());
+ return 0;
+ }
+
+ if (!symbol->isFunction()) {
+ error(line, "function name expected", call->getName().c_str());
+ return 0;
+ }
+
+ return static_cast<const TFunction*>(symbol);
+}
+
+//
+// Initializers show up in several places in the grammar. Have one set of
+// code to handle them here.
+//
+bool TParseContext::executeInitializer(const TSourceLoc& line, TString& identifier, TPublicType& pType,
+ TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
+{
+ TType type = TType(pType);
+
+ if (variable == 0) {
+ if (reservedErrorCheck(line, identifier))
+ return true;
+
+ if (voidErrorCheck(line, identifier, pType))
+ return true;
+
+ //
+ // add variable to symbol table
+ //
+ variable = new TVariable(&identifier, type);
+ if (! symbolTable.insert(*variable)) {
+ error(line, "redefinition", variable->getName().c_str());
+ return true;
+ // don't delete variable, it's used by error recovery, and the pool
+ // pop will take care of the memory
+ }
+ }
+
+ //
+ // identifier must be of type constant, a global, or a temporary
+ //
+ TQualifier qualifier = variable->getType().getQualifier();
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
+ error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString());
+ return true;
+ }
+ //
+ // test for and propagate constant
+ //
+
+ if (qualifier == EvqConst) {
+ if (qualifier != initializer->getType().getQualifier()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " assigning non-constant to", "=", extraInfo.c_str());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ if (type != initializer->getType()) {
+ error(line, " non-matching types for const initializer ",
+ variable->getType().getQualifierString());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ if (initializer->getAsConstantUnion()) {
+ variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
+ } else if (initializer->getAsSymbolNode()) {
+ const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol());
+ const TVariable* tVar = static_cast<const TVariable*>(symbol);
+
+ ConstantUnion* constArray = tVar->getConstPointer();
+ variable->shareConstPointer(constArray);
+ } else {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "'" << variable->getType().getCompleteString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, " cannot assign to", "=", extraInfo.c_str());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ }
+
+ if (qualifier != EvqConst) {
+ TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
+ intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
+ if (intermNode == 0) {
+ assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+ return true;
+ }
+ } else
+ intermNode = 0;
+
+ return false;
+}
+
+bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
+{
+ ASSERT(aggrNode != NULL);
+ if (!aggrNode->isConstructor())
+ return false;
+
+ bool allConstant = true;
+
+ // check if all the child nodes are constants so that they can be inserted into
+ // the parent node
+ TIntermSequence &sequence = aggrNode->getSequence() ;
+ for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) {
+ if (!(*p)->getAsTyped()->getAsConstantUnion())
+ return false;
+ }
+
+ return allConstant;
+}
+
+// This function is used to test for the correctness of the parameters passed to various constructor functions
+// and also convert them to the right datatype if it is allowed and required.
+//
+// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
+//
+TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, const TSourceLoc& line)
+{
+ if (node == 0)
+ return 0;
+
+ TIntermAggregate* aggrNode = node->getAsAggregate();
+
+ TFieldList::const_iterator memberFields;
+ if (op == EOpConstructStruct)
+ memberFields = type->getStruct()->fields().begin();
+
+ TType elementType = *type;
+ if (type->isArray())
+ elementType.clearArrayness();
+
+ bool singleArg;
+ if (aggrNode) {
+ if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
+ singleArg = true;
+ else
+ singleArg = false;
+ } else
+ singleArg = true;
+
+ TIntermTyped *newNode;
+ if (singleArg) {
+ // If structure constructor or array constructor is being called
+ // for only one parameter inside the structure, we need to call constructStruct function once.
+ if (type->isArray())
+ newNode = constructStruct(node, &elementType, 1, node->getLine(), false);
+ else if (op == EOpConstructStruct)
+ newNode = constructStruct(node, (*memberFields)->type(), 1, node->getLine(), false);
+ else
+ newNode = constructBuiltIn(type, op, node, node->getLine(), false);
+
+ if (newNode && newNode->getAsAggregate()) {
+ TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type);
+ if (constConstructor)
+ return constConstructor;
+ }
+
+ return newNode;
+ }
+
+ //
+ // Handle list of arguments.
+ //
+ TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor
+ // if the structure constructor contains more than one parameter, then construct
+ // each parameter
+
+ int paramCount = 0; // keeps a track of the constructor parameter number being checked
+
+ // for each parameter to the constructor call, check to see if the right type is passed or convert them
+ // to the right type if possible (and allowed).
+ // for structure constructors, just check if the right type is passed, no conversion is allowed.
+
+ for (TIntermSequence::iterator p = sequenceVector.begin();
+ p != sequenceVector.end(); p++, paramCount++) {
+ if (type->isArray())
+ newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true);
+ else if (op == EOpConstructStruct)
+ newNode = constructStruct(*p, memberFields[paramCount]->type(), paramCount+1, node->getLine(), true);
+ else
+ newNode = constructBuiltIn(type, op, *p, node->getLine(), true);
+
+ if (newNode) {
+ *p = newNode;
+ }
+ }
+
+ TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
+ TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
+ if (constConstructor)
+ return constConstructor;
+
+ return constructor;
+}
+
+TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
+{
+ bool canBeFolded = areAllChildConst(aggrNode);
+ aggrNode->setType(type);
+ if (canBeFolded) {
+ bool returnVal = false;
+ ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
+ if (aggrNode->getSequence().size() == 1) {
+ returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true);
+ }
+ else {
+ returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type);
+ }
+ if (returnVal)
+ return 0;
+
+ return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
+ }
+
+ return 0;
+}
+
+// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
+// for the parameter to the constructor (passed to this function). Essentially, it converts
+// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
+// float, then float is converted to int.
+//
+// Returns 0 for an error or the constructed node.
+//
+TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, const TSourceLoc& line, bool subset)
+{
+ TIntermTyped* newNode;
+ TOperator basicOp;
+
+ //
+ // First, convert types as needed.
+ //
+ switch (op) {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ case EOpConstructFloat:
+ basicOp = EOpConstructFloat;
+ break;
+
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ basicOp = EOpConstructInt;
+ break;
+
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ basicOp = EOpConstructBool;
+ break;
+
+ default:
+ error(line, "unsupported construction", "");
+ recover();
+
+ return 0;
+ }
+ newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable);
+ if (newNode == 0) {
+ error(line, "can't convert", "constructor");
+ return 0;
+ }
+
+ //
+ // Now, if there still isn't an operation to do the construction, and we need one, add one.
+ //
+
+ // Otherwise, skip out early.
+ if (subset || (newNode != node && newNode->getType() == *type))
+ return newNode;
+
+ // setAggregateOperator will insert a new node for the constructor, as needed.
+ return intermediate.setAggregateOperator(newNode, op, line);
+}
+
+// This function tests for the type of the parameters to the structures constructors. Raises
+// an error message if the expected type does not match the parameter passed to the constructor.
+//
+// Returns 0 for an error or the input node itself if the expected and the given parameter types match.
+//
+TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, const TSourceLoc& line, bool subset)
+{
+ if (*type == node->getAsTyped()->getType()) {
+ if (subset)
+ return node->getAsTyped();
+ else
+ return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line);
+ } else {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "cannot convert parameter " << paramCount
+ << " from '" << node->getAsTyped()->getType().getBasicString()
+ << "' to '" << type->getBasicString() << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "constructor", extraInfo.c_str());
+ recover();
+ }
+
+ return 0;
+}
+
+//
+// This function returns the tree representation for the vector field(s) being accessed from contant vector.
+// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
+// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
+// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
+// a constant matrix.
+//
+TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, const TSourceLoc& line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+
+ ConstantUnion *unionArray;
+ if (tempConstantNode) {
+ unionArray = tempConstantNode->getUnionArrayPointer();
+
+ if (!unionArray) {
+ return node;
+ }
+ } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
+ error(line, "Cannot offset into the vector", "Error");
+ recover();
+
+ return 0;
+ }
+
+ ConstantUnion* constArray = new ConstantUnion[fields.num];
+
+ for (int i = 0; i < fields.num; i++) {
+ if (fields.offsets[i] >= node->getType().getNominalSize()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "vector field selection out of range '" << fields.offsets[i] << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "[", extraInfo.c_str());
+ recover();
+ fields.offsets[i] = 0;
+ }
+
+ constArray[i] = unionArray[fields.offsets[i]];
+
+ }
+ typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
+ return typedNode;
+}
+
+//
+// This function returns the column being accessed from a constant matrix. The values are retrieved from
+// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
+// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
+// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
+//
+TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, const TSourceLoc& line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+
+ if (index >= node->getType().getNominalSize()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "matrix field selection out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "[", extraInfo.c_str());
+ recover();
+ index = 0;
+ }
+
+ if (tempConstantNode) {
+ ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
+ int size = tempConstantNode->getType().getNominalSize();
+ typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
+ } else {
+ error(line, "Cannot offset into the matrix", "Error");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+
+//
+// This function returns an element of an array accessed from a constant array. The values are retrieved from
+// the symbol table and parse-tree is built for the type of the element. The input
+// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
+// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
+//
+TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+ TType arrayElementType = node->getType();
+ arrayElementType.clearArrayness();
+
+ if (index >= node->getType().getArraySize()) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "array field selection out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "[", extraInfo.c_str());
+ recover();
+ index = 0;
+ }
+
+ if (tempConstantNode) {
+ size_t arrayElementSize = arrayElementType.getObjectSize();
+ ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
+ typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
+ } else {
+ error(line, "Cannot offset into the array", "Error");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+
+//
+// This function returns the value of a particular field inside a constant structure from the symbol table.
+// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
+// function and returns the parse-tree with the values of the embedded/nested struct.
+//
+TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, const TSourceLoc& line)
+{
+ const TFieldList& fields = node->getType().getStruct()->fields();
+
+ size_t instanceSize = 0;
+ for (size_t index = 0; index < fields.size(); ++index) {
+ if (fields[index]->name() == identifier) {
+ break;
+ } else {
+ instanceSize += fields[index]->type()->getObjectSize();
+ }
+ }
+
+ TIntermTyped* typedNode = 0;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+ if (tempConstantNode) {
+ ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
+
+ typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
+ } else {
+ error(line, "Cannot offset into the structure", "Error");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+bool TParseContext::enterStructDeclaration(const TSourceLoc& line, const TString& identifier)
+{
+ ++structNestingLevel;
+
+ // Embedded structure definitions are not supported per GLSL ES spec.
+ // They aren't allowed in GLSL either, but we need to detect this here
+ // so we don't rely on the GLSL compiler to catch it.
+ if (structNestingLevel > 1) {
+ error(line, "", "Embedded struct definitions are not allowed");
+ return true;
+ }
+
+ return false;
+}
+
+void TParseContext::exitStructDeclaration()
+{
+ --structNestingLevel;
+}
+
+namespace {
+
+const int kWebGLMaxStructNesting = 4;
+
+} // namespace
+
+bool TParseContext::structNestingErrorCheck(const TSourceLoc& line, const TField& field)
+{
+ if (!isWebGLBasedSpec(shaderSpec)) {
+ return false;
+ }
+
+ if (field.type()->getBasicType() != EbtStruct) {
+ return false;
+ }
+
+ // We're already inside a structure definition at this point, so add
+ // one to the field's struct nesting.
+ if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "Reference of struct type " << field.name()
+ << " exceeds maximum struct nesting of " << kWebGLMaxStructNesting;
+ std::string extraInfo = extraInfoStream.str();
+ error(line, "", "", extraInfo.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Parse an array index expression
+//
+TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression)
+{
+ TIntermTyped *indexedExpression = NULL;
+
+ if (!baseExpression->isArray() && !baseExpression->isMatrix() && !baseExpression->isVector())
+ {
+ if (baseExpression->getAsSymbolNode())
+ {
+ error(location, " left of '[' is not of type array, matrix, or vector ", baseExpression->getAsSymbolNode()->getSymbol().c_str());
+ }
+ else
+ {
+ error(location, " left of '[' is not of type array, matrix, or vector ", "expression");
+ }
+ recover();
+ }
+
+ if (indexExpression->getQualifier() == EvqConst)
+ {
+ int index = indexExpression->getAsConstantUnion()->getIConst(0);
+ if (index < 0)
+ {
+ std::stringstream infoStream;
+ infoStream << index;
+ std::string info = infoStream.str();
+ error(location, "negative index", info.c_str());
+ recover();
+ index = 0;
+ }
+ if (baseExpression->getType().getQualifier() == EvqConst)
+ {
+ if (baseExpression->isArray())
+ {
+ // constant folding for arrays
+ indexedExpression = addConstArrayNode(index, baseExpression, location);
+ }
+ else if (baseExpression->isVector())
+ {
+ // constant folding for vectors
+ TVectorFields fields;
+ fields.num = 1;
+ fields.offsets[0] = index; // need to do it this way because v.xy sends fields integer array
+ indexedExpression = addConstVectorNode(fields, baseExpression, location);
+ }
+ else if (baseExpression->isMatrix())
+ {
+ // constant folding for matrices
+ indexedExpression = addConstMatrixNode(index, baseExpression, location);
+ }
+ }
+ else
+ {
+ if (baseExpression->isArray())
+ {
+ if (index >= baseExpression->getType().getArraySize())
+ {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "array index out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(location, "", "[", extraInfo.c_str());
+ recover();
+ index = baseExpression->getType().getArraySize() - 1;
+ }
+ else if (baseExpression->getQualifier() == EvqFragData && index > 0 && !isExtensionEnabled("GL_EXT_draw_buffers"))
+ {
+ error(location, "", "[", "array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is disabled");
+ recover();
+ index = 0;
+ }
+ }
+ else if ((baseExpression->isVector() || baseExpression->isMatrix()) && baseExpression->getType().getNominalSize() <= index)
+ {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "field selection out of range '" << index << "'";
+ std::string extraInfo = extraInfoStream.str();
+ error(location, "", "[", extraInfo.c_str());
+ recover();
+ index = baseExpression->getType().getNominalSize() - 1;
+ }
+
+ indexExpression->getAsConstantUnion()->getUnionArrayPointer()->setIConst(index);
+ indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location);
+ }
+ }
+ else
+ {
+ indexedExpression = intermediate.addIndex(EOpIndexIndirect, baseExpression, indexExpression, location);
+ }
+
+ if (indexedExpression == 0)
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ indexedExpression = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), location);
+ }
+ else if (baseExpression->isArray())
+ {
+ const TType &baseType = baseExpression->getType();
+ if (baseType.getStruct())
+ {
+ TType copyOfType(baseType.getStruct());
+ indexedExpression->setType(copyOfType);
+ }
+ else
+ {
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), EvqTemporary, baseExpression->getNominalSize(), baseExpression->isMatrix()));
+ }
+
+ if (baseExpression->getType().getQualifier() == EvqConst)
+ {
+ indexedExpression->getTypePointer()->setQualifier(EvqConst);
+ }
+ }
+ else if (baseExpression->isMatrix())
+ {
+ TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier, baseExpression->getNominalSize()));
+ }
+ else if (baseExpression->isVector())
+ {
+ TQualifier qualifier = baseExpression->getType().getQualifier() == EvqConst ? EvqConst : EvqTemporary;
+ indexedExpression->setType(TType(baseExpression->getBasicType(), baseExpression->getPrecision(), qualifier));
+ }
+ else
+ {
+ indexedExpression->setType(baseExpression->getType());
+ }
+
+ return indexedExpression;
+}
+
+//
+// Parse an array of strings using yyparse.
+//
+// Returns 0 for success.
+//
+int PaParseStrings(size_t count, const char* const string[], const int length[],
+ TParseContext* context) {
+ if ((count == 0) || (string == NULL))
+ return 1;
+
+ if (glslang_initialize(context))
+ return 1;
+
+ int error = glslang_scan(count, string, length, context);
+ if (!error)
+ error = glslang_parse(context);
+
+ glslang_finalize(context);
+
+ return (error == 0) && (context->numErrors() == 0) ? 0 : 1;
+}
+
+
+
diff --git a/src/compiler/ParseHelper.h b/src/compiler/ParseHelper.h
new file mode 100644
index 00000000..c2b3c3f7
--- /dev/null
+++ b/src/compiler/ParseHelper.h
@@ -0,0 +1,134 @@
+//
+// 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.
+//
+#ifndef _PARSER_HELPER_INCLUDED_
+#define _PARSER_HELPER_INCLUDED_
+
+#include "compiler/Diagnostics.h"
+#include "compiler/DirectiveHandler.h"
+#include "compiler/localintermediate.h"
+#include "compiler/preprocessor/Preprocessor.h"
+#include "compiler/ShHandle.h"
+#include "compiler/SymbolTable.h"
+
+struct TMatrixFields {
+ bool wholeRow;
+ bool wholeCol;
+ int row;
+ int col;
+};
+
+//
+// The following are extra variables needed during parsing, grouped together so
+// they can be passed to the parser without needing a global.
+//
+struct TParseContext {
+ TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) :
+ intermediate(interm),
+ symbolTable(symt),
+ shaderType(type),
+ shaderSpec(spec),
+ compileOptions(options),
+ sourcePath(sourcePath),
+ treeRoot(0),
+ loopNestingLevel(0),
+ structNestingLevel(0),
+ currentFunctionType(NULL),
+ functionReturnsValue(false),
+ checksPrecisionErrors(checksPrecErrors),
+ diagnostics(is),
+ directiveHandler(ext, diagnostics),
+ preprocessor(&diagnostics, &directiveHandler),
+ scanner(NULL) { }
+ TIntermediate& intermediate; // to hold and build a parse tree
+ TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
+ ShShaderType shaderType; // vertex or fragment language (future: pack or unpack)
+ ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
+ int compileOptions;
+ const char* sourcePath; // Path of source file or NULL.
+ TIntermNode* treeRoot; // root of parse tree being created
+ int loopNestingLevel; // 0 if outside all loops
+ int structNestingLevel; // incremented while parsing a struct declaration
+ const TType* currentFunctionType; // the return type of the function that's currently being parsed
+ bool functionReturnsValue; // true if a non-void function has a return
+ bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
+ bool fragmentPrecisionHigh; // true if highp precision is supported in the fragment language.
+ TString HashErrMsg;
+ TDiagnostics diagnostics;
+ TDirectiveHandler directiveHandler;
+ pp::Preprocessor preprocessor;
+ void* scanner;
+
+ int numErrors() const { return diagnostics.numErrors(); }
+ TInfoSink& infoSink() { return diagnostics.infoSink(); }
+ void error(const TSourceLoc& loc, const char *reason, const char* token,
+ const char* extraInfo="");
+ void warning(const TSourceLoc& loc, const char* reason, const char* token,
+ const char* extraInfo="");
+ void trace(const char* str);
+ void recover();
+
+ bool parseVectorFields(const TString&, int vecSize, TVectorFields&, const TSourceLoc& line);
+ bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, const TSourceLoc& line);
+
+ bool reservedErrorCheck(const TSourceLoc& line, const TString& identifier);
+ void assignError(const TSourceLoc& line, const char* op, TString left, TString right);
+ void unaryOpError(const TSourceLoc& line, const char* op, TString operand);
+ void binaryOpError(const TSourceLoc& line, const char* op, TString left, TString right);
+ bool precisionErrorCheck(const TSourceLoc& line, TPrecision precision, TBasicType type);
+ bool lValueErrorCheck(const TSourceLoc& line, const char* op, TIntermTyped*);
+ bool constErrorCheck(TIntermTyped* node);
+ bool integerErrorCheck(TIntermTyped* node, const char* token);
+ bool globalErrorCheck(const TSourceLoc& line, bool global, const char* token);
+ bool constructorErrorCheck(const TSourceLoc& line, TIntermNode*, TFunction&, TOperator, TType*);
+ bool arraySizeErrorCheck(const TSourceLoc& line, TIntermTyped* expr, int& size);
+ bool arrayQualifierErrorCheck(const TSourceLoc& line, TPublicType type);
+ bool arrayTypeErrorCheck(const TSourceLoc& line, TPublicType type);
+ bool arrayErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType type, TVariable*& variable);
+ bool voidErrorCheck(const TSourceLoc&, const TString&, const TPublicType&);
+ bool boolErrorCheck(const TSourceLoc&, const TIntermTyped*);
+ bool boolErrorCheck(const TSourceLoc&, const TPublicType&);
+ bool samplerErrorCheck(const TSourceLoc& line, const TPublicType& pType, const char* reason);
+ bool structQualifierErrorCheck(const TSourceLoc& line, const TPublicType& pType);
+ bool parameterSamplerErrorCheck(const TSourceLoc& line, TQualifier qualifier, const TType& type);
+ bool nonInitConstErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, bool array);
+ bool nonInitErrorCheck(const TSourceLoc& line, TString& identifier, TPublicType& type, TVariable*& variable);
+ bool paramErrorCheck(const TSourceLoc& line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
+ bool extensionErrorCheck(const TSourceLoc& line, const TString&);
+
+ const TPragma& pragma() const { return directiveHandler.pragma(); }
+ const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); }
+ bool supportsExtension(const char* extension);
+ bool isExtensionEnabled(const char* extension) const;
+
+ bool containsSampler(TType& type);
+ bool areAllChildConst(TIntermAggregate* aggrNode);
+ const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, bool *builtIn = 0);
+ bool executeInitializer(const TSourceLoc& line, TString& identifier, TPublicType& pType,
+ TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
+
+ TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&);
+ TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
+ TIntermTyped* constructStruct(TIntermNode*, TType*, int, const TSourceLoc&, bool subset);
+ TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, const TSourceLoc&, bool subset);
+ TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&);
+ TIntermTyped* addConstMatrixNode(int , TIntermTyped*, const TSourceLoc&);
+ TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, const TSourceLoc& line);
+ TIntermTyped* addConstStruct(TString& , TIntermTyped*, const TSourceLoc&);
+ TIntermTyped* addIndexExpression(TIntermTyped *baseExpression, const TSourceLoc& location, TIntermTyped *indexExpression);
+
+ // Performs an error check for embedded struct declarations.
+ // Returns true if an error was raised due to the declaration of
+ // this struct.
+ bool enterStructDeclaration(const TSourceLoc& line, const TString& identifier);
+ void exitStructDeclaration();
+
+ bool structNestingErrorCheck(const TSourceLoc& line, const TField& field);
+};
+
+int PaParseStrings(size_t count, const char* const string[], const int length[],
+ TParseContext* context);
+
+#endif // _PARSER_HELPER_INCLUDED_
diff --git a/src/compiler/PoolAlloc.cpp b/src/compiler/PoolAlloc.cpp
new file mode 100644
index 00000000..eb993567
--- /dev/null
+++ b/src/compiler/PoolAlloc.cpp
@@ -0,0 +1,294 @@
+//
+// 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.
+//
+
+#include "compiler/PoolAlloc.h"
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+#include <stdio.h>
+
+#include "common/angleutils.h"
+#include "compiler/InitializeGlobals.h"
+#include "compiler/osinclude.h"
+
+OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX;
+
+bool InitializePoolIndex()
+{
+ assert(PoolIndex == OS_INVALID_TLS_INDEX);
+
+ PoolIndex = OS_AllocTLSIndex();
+ return PoolIndex != OS_INVALID_TLS_INDEX;
+}
+
+void FreePoolIndex()
+{
+ assert(PoolIndex != OS_INVALID_TLS_INDEX);
+
+ OS_FreeTLSIndex(PoolIndex);
+ PoolIndex = OS_INVALID_TLS_INDEX;
+}
+
+TPoolAllocator* GetGlobalPoolAllocator()
+{
+ assert(PoolIndex != OS_INVALID_TLS_INDEX);
+ return static_cast<TPoolAllocator*>(OS_GetTLSValue(PoolIndex));
+}
+
+void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
+{
+ assert(PoolIndex != OS_INVALID_TLS_INDEX);
+ OS_SetTLSValue(PoolIndex, poolAllocator);
+}
+
+//
+// Implement the functionality of the TPoolAllocator class, which
+// is documented in PoolAlloc.h.
+//
+TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
+ pageSize(growthIncrement),
+ alignment(allocationAlignment),
+ freeList(0),
+ inUseList(0),
+ numCalls(0),
+ totalBytes(0)
+{
+ //
+ // Don't allow page sizes we know are smaller than all common
+ // OS page sizes.
+ //
+ if (pageSize < 4*1024)
+ pageSize = 4*1024;
+
+ //
+ // A large currentPageOffset indicates a new page needs to
+ // be obtained to allocate memory.
+ //
+ currentPageOffset = pageSize;
+
+ //
+ // Adjust alignment to be at least pointer aligned and
+ // power of 2.
+ //
+ size_t minAlign = sizeof(void*);
+ alignment &= ~(minAlign - 1);
+ if (alignment < minAlign)
+ alignment = minAlign;
+ size_t a = 1;
+ while (a < alignment)
+ a <<= 1;
+ alignment = a;
+ alignmentMask = a - 1;
+
+ //
+ // Align header skip
+ //
+ headerSkip = minAlign;
+ if (headerSkip < sizeof(tHeader)) {
+ headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
+ }
+}
+
+TPoolAllocator::~TPoolAllocator()
+{
+ while (inUseList) {
+ tHeader* next = inUseList->nextPage;
+ inUseList->~tHeader();
+ delete [] reinterpret_cast<char*>(inUseList);
+ inUseList = next;
+ }
+
+ // We should not check the guard blocks
+ // here, because we did it already when the block was
+ // placed into the free list.
+ //
+ while (freeList) {
+ tHeader* next = freeList->nextPage;
+ delete [] reinterpret_cast<char*>(freeList);
+ freeList = next;
+ }
+}
+
+// Support MSVC++ 6.0
+const unsigned char TAllocation::guardBlockBeginVal = 0xfb;
+const unsigned char TAllocation::guardBlockEndVal = 0xfe;
+const unsigned char TAllocation::userDataFill = 0xcd;
+
+#ifdef GUARD_BLOCKS
+ const size_t TAllocation::guardBlockSize = 16;
+#else
+ const size_t TAllocation::guardBlockSize = 0;
+#endif
+
+//
+// Check a single guard block for damage
+//
+void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
+{
+#ifdef GUARD_BLOCKS
+ for (size_t x = 0; x < guardBlockSize; x++) {
+ if (blockMem[x] != val) {
+ char assertMsg[80];
+
+ // We don't print the assert message. It's here just to be helpful.
+#if defined(_MSC_VER)
+ snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %Iu byte allocation at 0x%p\n",
+ locText, size, data());
+#else
+ snprintf(assertMsg, sizeof(assertMsg), "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n",
+ locText, size, data());
+#endif
+ assert(0 && "PoolAlloc: Damage in guard block");
+ }
+ }
+#endif
+}
+
+
+void TPoolAllocator::push()
+{
+ tAllocState state = { currentPageOffset, inUseList };
+
+ stack.push_back(state);
+
+ //
+ // Indicate there is no current page to allocate from.
+ //
+ currentPageOffset = pageSize;
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred since the last push(), or since the
+// last pop(), or since the object's creation.
+//
+// The deallocated pages are saved for future allocations.
+//
+void TPoolAllocator::pop()
+{
+ if (stack.size() < 1)
+ return;
+
+ tHeader* page = stack.back().page;
+ currentPageOffset = stack.back().offset;
+
+ while (inUseList != page) {
+ // invoke destructor to free allocation list
+ inUseList->~tHeader();
+
+ tHeader* nextInUse = inUseList->nextPage;
+ if (inUseList->pageCount > 1)
+ delete [] reinterpret_cast<char*>(inUseList);
+ else {
+ inUseList->nextPage = freeList;
+ freeList = inUseList;
+ }
+ inUseList = nextInUse;
+ }
+
+ stack.pop_back();
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred.
+//
+void TPoolAllocator::popAll()
+{
+ while (stack.size() > 0)
+ pop();
+}
+
+void* TPoolAllocator::allocate(size_t numBytes)
+{
+ //
+ // Just keep some interesting statistics.
+ //
+ ++numCalls;
+ totalBytes += numBytes;
+
+ // If we are using guard blocks, all allocations are bracketed by
+ // them: [guardblock][allocation][guardblock]. numBytes is how
+ // much memory the caller asked for. allocationSize is the total
+ // size including guard blocks. In release build,
+ // guardBlockSize=0 and this all gets optimized away.
+ size_t allocationSize = TAllocation::allocationSize(numBytes);
+ // Detect integer overflow.
+ if (allocationSize < numBytes)
+ return 0;
+
+ //
+ // Do the allocation, most likely case first, for efficiency.
+ // This step could be moved to be inline sometime.
+ //
+ if (allocationSize <= pageSize - currentPageOffset) {
+ //
+ // Safe to allocate from currentPageOffset.
+ //
+ unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset;
+ currentPageOffset += allocationSize;
+ currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, memory, numBytes);
+ }
+
+ if (allocationSize > pageSize - headerSkip) {
+ //
+ // Do a multi-page allocation. Don't mix these with the others.
+ // The OS is efficient and allocating and free-ing multiple pages.
+ //
+ size_t numBytesToAlloc = allocationSize + headerSkip;
+ // Detect integer overflow.
+ if (numBytesToAlloc < allocationSize)
+ return 0;
+
+ tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
+ if (memory == 0)
+ return 0;
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
+ inUseList = memory;
+
+ currentPageOffset = pageSize; // make next allocation come from a new page
+
+ // No guard blocks for multi-page allocations (yet)
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip);
+ }
+
+ //
+ // Need a simple page to allocate from.
+ //
+ tHeader* memory;
+ if (freeList) {
+ memory = freeList;
+ freeList = freeList->nextPage;
+ } else {
+ memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
+ if (memory == 0)
+ return 0;
+ }
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, 1);
+ inUseList = memory;
+
+ unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip;
+ currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, ret, numBytes);
+}
+
+
+//
+// Check all allocations in a list for damage by calling check on each.
+//
+void TAllocation::checkAllocList() const
+{
+ for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
+ alloc->check();
+}
diff --git a/src/compiler/PoolAlloc.h b/src/compiler/PoolAlloc.h
new file mode 100644
index 00000000..edd249c4
--- /dev/null
+++ b/src/compiler/PoolAlloc.h
@@ -0,0 +1,300 @@
+//
+// 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.
+//
+
+#ifndef _POOLALLOC_INCLUDED_
+#define _POOLALLOC_INCLUDED_
+
+#ifdef _DEBUG
+#define GUARD_BLOCKS // define to enable guard block sanity checking
+#endif
+
+//
+// This header defines an allocator that can be used to efficiently
+// allocate a large number of small requests for heap memory, with the
+// intention that they are not individually deallocated, but rather
+// collectively deallocated at one time.
+//
+// This simultaneously
+//
+// * Makes each individual allocation much more efficient; the
+// typical allocation is trivial.
+// * Completely avoids the cost of doing individual deallocation.
+// * Saves the trouble of tracking down and plugging a large class of leaks.
+//
+// Individual classes can use this allocator by supplying their own
+// new and delete methods.
+//
+// STL containers can use this allocator by using the pool_allocator
+// class as the allocator (second) template argument.
+//
+
+#include <stddef.h>
+#include <string.h>
+#include <vector>
+
+// If we are using guard blocks, we must track each indivual
+// allocation. If we aren't using guard blocks, these
+// never get instantiated, so won't have any impact.
+//
+
+class TAllocation {
+public:
+ TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) :
+ size(size), mem(mem), prevAlloc(prev) {
+ // Allocations are bracketed:
+ // [allocationHeader][initialGuardBlock][userData][finalGuardBlock]
+ // This would be cleaner with if (guardBlockSize)..., but that
+ // makes the compiler print warnings about 0 length memsets,
+ // even with the if() protecting them.
+#ifdef GUARD_BLOCKS
+ memset(preGuard(), guardBlockBeginVal, guardBlockSize);
+ memset(data(), userDataFill, size);
+ memset(postGuard(), guardBlockEndVal, guardBlockSize);
+#endif
+ }
+
+ void check() const {
+ checkGuardBlock(preGuard(), guardBlockBeginVal, "before");
+ checkGuardBlock(postGuard(), guardBlockEndVal, "after");
+ }
+
+ void checkAllocList() const;
+
+ // Return total size needed to accomodate user buffer of 'size',
+ // plus our tracking data.
+ inline static size_t allocationSize(size_t size) {
+ return size + 2 * guardBlockSize + headerSize();
+ }
+
+ // Offset from surrounding buffer to get to user data buffer.
+ inline static unsigned char* offsetAllocation(unsigned char* m) {
+ return m + guardBlockSize + headerSize();
+ }
+
+private:
+ void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const;
+
+ // Find offsets to pre and post guard blocks, and user data buffer
+ unsigned char* preGuard() const { return mem + headerSize(); }
+ unsigned char* data() const { return preGuard() + guardBlockSize; }
+ unsigned char* postGuard() const { return data() + size; }
+
+ size_t size; // size of the user data area
+ unsigned char* mem; // beginning of our allocation (pts to header)
+ TAllocation* prevAlloc; // prior allocation in the chain
+
+ // Support MSVC++ 6.0
+ const static unsigned char guardBlockBeginVal;
+ const static unsigned char guardBlockEndVal;
+ const static unsigned char userDataFill;
+
+ const static size_t guardBlockSize;
+#ifdef GUARD_BLOCKS
+ inline static size_t headerSize() { return sizeof(TAllocation); }
+#else
+ inline static size_t headerSize() { return 0; }
+#endif
+};
+
+//
+// There are several stacks. One is to track the pushing and popping
+// of the user, and not yet implemented. The others are simply a
+// repositories of free pages or used pages.
+//
+// Page stacks are linked together with a simple header at the beginning
+// of each allocation obtained from the underlying OS. Multi-page allocations
+// are returned to the OS. Individual page allocations are kept for future
+// re-use.
+//
+// The "page size" used is not, nor must it match, the underlying OS
+// page size. But, having it be about that size or equal to a set of
+// pages is likely most optimal.
+//
+class TPoolAllocator {
+public:
+ TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16);
+
+ //
+ // Don't call the destructor just to free up the memory, call pop()
+ //
+ ~TPoolAllocator();
+
+ //
+ // Call push() to establish a new place to pop memory too. Does not
+ // have to be called to get things started.
+ //
+ void push();
+
+ //
+ // Call pop() to free all memory allocated since the last call to push(),
+ // or if no last call to push, frees all memory since first allocation.
+ //
+ void pop();
+
+ //
+ // Call popAll() to free all memory allocated.
+ //
+ void popAll();
+
+ //
+ // Call allocate() to actually acquire memory. Returns 0 if no memory
+ // available, otherwise a properly aligned pointer to 'numBytes' of memory.
+ //
+ void* allocate(size_t numBytes);
+
+ //
+ // There is no deallocate. The point of this class is that
+ // deallocation can be skipped by the user of it, as the model
+ // of use is to simultaneously deallocate everything at once
+ // by calling pop(), and to not have to solve memory leak problems.
+ //
+
+protected:
+ friend struct tHeader;
+
+ struct tHeader {
+ tHeader(tHeader* nextPage, size_t pageCount) :
+ nextPage(nextPage),
+ pageCount(pageCount)
+#ifdef GUARD_BLOCKS
+ , lastAllocation(0)
+#endif
+ { }
+
+ ~tHeader() {
+#ifdef GUARD_BLOCKS
+ if (lastAllocation)
+ lastAllocation->checkAllocList();
+#endif
+ }
+
+ tHeader* nextPage;
+ size_t pageCount;
+#ifdef GUARD_BLOCKS
+ TAllocation* lastAllocation;
+#endif
+ };
+
+ struct tAllocState {
+ size_t offset;
+ tHeader* page;
+ };
+ typedef std::vector<tAllocState> tAllocStack;
+
+ // Track allocations if and only if we're using guard blocks
+ void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) {
+#ifdef GUARD_BLOCKS
+ new(memory) TAllocation(numBytes, memory, block->lastAllocation);
+ block->lastAllocation = reinterpret_cast<TAllocation*>(memory);
+#endif
+ // This is optimized entirely away if GUARD_BLOCKS is not defined.
+ return TAllocation::offsetAllocation(memory);
+ }
+
+ size_t pageSize; // granularity of allocation from the OS
+ size_t alignment; // all returned allocations will be aligned at
+ // this granularity, which will be a power of 2
+ size_t alignmentMask;
+ size_t headerSkip; // amount of memory to skip to make room for the
+ // header (basically, size of header, rounded
+ // up to make it aligned
+ size_t currentPageOffset; // next offset in top of inUseList to allocate from
+ tHeader* freeList; // list of popped memory
+ tHeader* inUseList; // list of all memory currently being used
+ tAllocStack stack; // stack of where to allocate from, to partition pool
+
+ int numCalls; // just an interesting statistic
+ size_t totalBytes; // just an interesting statistic
+private:
+ TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator
+ TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor
+};
+
+
+//
+// There could potentially be many pools with pops happening at
+// different times. But a simple use is to have a global pop
+// with everyone using the same global allocator.
+//
+extern TPoolAllocator* GetGlobalPoolAllocator();
+extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator);
+
+//
+// This STL compatible allocator is intended to be used as the allocator
+// parameter to templatized STL containers, like vector and map.
+//
+// It will use the pools for allocation, and not
+// do any deallocation, but will still do destruction.
+//
+template<class T>
+class pool_allocator {
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ template<class Other>
+ struct rebind {
+ typedef pool_allocator<Other> other;
+ };
+ pointer address(reference x) const { return &x; }
+ const_pointer address(const_reference x) const { return &x; }
+
+ pool_allocator() : allocator(GetGlobalPoolAllocator()) { }
+ pool_allocator(TPoolAllocator& a) : allocator(&a) { }
+ pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
+
+ template <class Other>
+ pool_allocator<T>& operator=(const pool_allocator<Other>& p) {
+ allocator = p.allocator;
+ return *this;
+ }
+
+ template<class Other>
+ pool_allocator(const pool_allocator<Other>& p) : allocator(&p.getAllocator()) { }
+
+#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR)
+ // libCStd on some platforms have a different allocate/deallocate interface.
+ // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be
+ // allocated, not the number of elements.
+ void* allocate(size_type n) {
+ return getAllocator().allocate(n);
+ }
+ void* allocate(size_type n, const void*) {
+ return getAllocator().allocate(n);
+ }
+ void deallocate(void*, size_type) {}
+#else
+ pointer allocate(size_type n) {
+ return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ pointer allocate(size_type n, const void*) {
+ return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ void deallocate(pointer, size_type) {}
+#endif // _RWSTD_ALLOCATOR
+
+ void construct(pointer p, const T& val) { new ((void *)p) T(val); }
+ void destroy(pointer p) { p->T::~T(); }
+
+ bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); }
+ bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); }
+
+ size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
+ size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
+
+ void setAllocator(TPoolAllocator* a) { allocator = a; }
+ TPoolAllocator& getAllocator() const { return *allocator; }
+
+protected:
+ TPoolAllocator* allocator;
+};
+
+#endif // _POOLALLOC_INCLUDED_
diff --git a/src/compiler/Pragma.h b/src/compiler/Pragma.h
new file mode 100644
index 00000000..2f744123
--- /dev/null
+++ b/src/compiler/Pragma.h
@@ -0,0 +1,19 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PRAGMA_H_
+#define COMPILER_PRAGMA_H_
+
+struct TPragma {
+ // By default optimization is turned on and debug is turned off.
+ TPragma() : optimize(true), debug(false) { }
+ TPragma(bool o, bool d) : optimize(o), debug(d) { }
+
+ bool optimize;
+ bool debug;
+};
+
+#endif // COMPILER_PRAGMA_H_
diff --git a/src/compiler/QualifierAlive.cpp b/src/compiler/QualifierAlive.cpp
new file mode 100644
index 00000000..92a6874e
--- /dev/null
+++ b/src/compiler/QualifierAlive.cpp
@@ -0,0 +1,58 @@
+//
+// 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.
+//
+
+#include "compiler/intermediate.h"
+
+class TAliveTraverser : public TIntermTraverser {
+public:
+ TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q)
+ {
+ }
+
+ bool wasFound() { return found; }
+
+protected:
+ bool found;
+ TQualifier qualifier;
+
+ void visitSymbol(TIntermSymbol*);
+ bool visitSelection(Visit, TIntermSelection*);
+};
+
+//
+// Report whether or not a variable of the given qualifier type
+// is guaranteed written. Not always possible to determine if
+// it is written conditionally.
+//
+// ?? It does not do this well yet, this is just a place holder
+// that simply determines if it was reference at all, anywhere.
+//
+bool QualifierWritten(TIntermNode* node, TQualifier qualifier)
+{
+ TAliveTraverser it(qualifier);
+
+ if (node)
+ node->traverse(&it);
+
+ return it.wasFound();
+}
+
+void TAliveTraverser::visitSymbol(TIntermSymbol* node)
+{
+ //
+ // If it's what we're looking for, record it.
+ //
+ if (node->getQualifier() == qualifier)
+ found = true;
+}
+
+bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node)
+{
+ if (wasFound())
+ return false;
+
+ return true;
+}
diff --git a/src/compiler/QualifierAlive.h b/src/compiler/QualifierAlive.h
new file mode 100644
index 00000000..872a06f7
--- /dev/null
+++ b/src/compiler/QualifierAlive.h
@@ -0,0 +1,7 @@
+//
+// 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.
+//
+
+bool QualifierWritten(TIntermNode* root, TQualifier);
diff --git a/src/compiler/RemoveTree.cpp b/src/compiler/RemoveTree.cpp
new file mode 100644
index 00000000..a4b8c1e6
--- /dev/null
+++ b/src/compiler/RemoveTree.cpp
@@ -0,0 +1,77 @@
+//
+// 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.
+//
+
+#include "compiler/intermediate.h"
+#include "compiler/RemoveTree.h"
+
+//
+// Code to recursively delete the intermediate tree.
+//
+
+class RemoveTree : public TIntermTraverser
+{
+public:
+ RemoveTree() : TIntermTraverser(false, false, true)
+ {
+ }
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+};
+
+void RemoveTree::visitSymbol(TIntermSymbol* node)
+{
+ delete node;
+}
+
+bool RemoveTree::visitBinary(Visit visit, TIntermBinary* node)
+{
+ delete node;
+
+ return true;
+}
+
+bool RemoveTree::visitUnary(Visit visit, TIntermUnary* node)
+{
+ delete node;
+
+ return true;
+}
+
+bool RemoveTree::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ delete node;
+
+ return true;
+}
+
+bool RemoveTree::visitSelection(Visit visit, TIntermSelection* node)
+{
+ delete node;
+
+ return true;
+}
+
+void RemoveTree::visitConstantUnion(TIntermConstantUnion* node)
+{
+ delete node;
+}
+
+//
+// Entry point.
+//
+void RemoveAllTreeNodes(TIntermNode* root)
+{
+ RemoveTree it;
+
+ root->traverse(&it);
+}
+
diff --git a/src/compiler/RemoveTree.h b/src/compiler/RemoveTree.h
new file mode 100644
index 00000000..97a82167
--- /dev/null
+++ b/src/compiler/RemoveTree.h
@@ -0,0 +1,7 @@
+//
+// 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.
+//
+
+void RemoveAllTreeNodes(TIntermNode*);
diff --git a/src/compiler/RenameFunction.h b/src/compiler/RenameFunction.h
new file mode 100644
index 00000000..3908bfdd
--- /dev/null
+++ b/src/compiler/RenameFunction.h
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_RENAME_FUNCTION
+#define COMPILER_RENAME_FUNCTION
+
+#include "compiler/intermediate.h"
+
+//
+// Renames a function, including its declaration and any calls to it.
+//
+class RenameFunction : public TIntermTraverser
+{
+public:
+ RenameFunction(const TString& oldFunctionName, const TString& newFunctionName)
+ : TIntermTraverser(true, false, false)
+ , mOldFunctionName(oldFunctionName)
+ , mNewFunctionName(newFunctionName) {}
+
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node)
+ {
+ TOperator op = node->getOp();
+ if ((op == EOpFunction || op == EOpFunctionCall) && node->getName() == mOldFunctionName)
+ node->setName(mNewFunctionName);
+ return true;
+ }
+
+private:
+ const TString mOldFunctionName;
+ const TString mNewFunctionName;
+};
+
+#endif // COMPILER_RENAME_FUNCTION
diff --git a/src/compiler/SearchSymbol.cpp b/src/compiler/SearchSymbol.cpp
new file mode 100644
index 00000000..9368f1a4
--- /dev/null
+++ b/src/compiler/SearchSymbol.cpp
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+// SearchSymbol is an AST traverser to detect the use of a given symbol name
+//
+
+#include "compiler/SearchSymbol.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/OutputHLSL.h"
+
+namespace sh
+{
+SearchSymbol::SearchSymbol(const TString &symbol) : mSymbol(symbol)
+{
+ match = false;
+}
+
+void SearchSymbol::traverse(TIntermNode *node)
+{
+ node->traverse(this);
+}
+
+void SearchSymbol::visitSymbol(TIntermSymbol *symbolNode)
+{
+ if (symbolNode->getSymbol() == mSymbol)
+ {
+ match = true;
+ }
+}
+
+bool SearchSymbol::foundMatch() const
+{
+ return match;
+}
+}
diff --git a/src/compiler/SearchSymbol.h b/src/compiler/SearchSymbol.h
new file mode 100644
index 00000000..6bc0b90f
--- /dev/null
+++ b/src/compiler/SearchSymbol.h
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+// SearchSymbol is an AST traverser to detect the use of a given symbol name
+//
+
+#ifndef COMPILER_SEARCHSYMBOL_H_
+#define COMPILER_SEARCHSYMBOL_H_
+
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+class SearchSymbol : public TIntermTraverser
+{
+ public:
+ SearchSymbol(const TString &symbol);
+
+ void traverse(TIntermNode *node);
+ void visitSymbol(TIntermSymbol *symbolNode);
+
+ bool foundMatch() const;
+
+ protected:
+ const TString &mSymbol;
+ bool match;
+};
+}
+
+#endif // COMPILER_SEARCHSYMBOL_H_
diff --git a/src/compiler/ShHandle.h b/src/compiler/ShHandle.h
new file mode 100644
index 00000000..eaf6f687
--- /dev/null
+++ b/src/compiler/ShHandle.h
@@ -0,0 +1,167 @@
+//
+// 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.
+//
+
+#ifndef _SHHANDLE_INCLUDED_
+#define _SHHANDLE_INCLUDED_
+
+//
+// Machine independent part of the compiler private objects
+// sent as ShHandle to the driver.
+//
+// This should not be included by driver code.
+//
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/BuiltInFunctionEmulator.h"
+#include "compiler/ExtensionBehavior.h"
+#include "compiler/HashNames.h"
+#include "compiler/InfoSink.h"
+#include "compiler/SymbolTable.h"
+#include "compiler/VariableInfo.h"
+#include "third_party/compiler/ArrayBoundsClamper.h"
+
+class LongNameMap;
+class TCompiler;
+class TDependencyGraph;
+class TranslatorHLSL;
+
+//
+// Helper function to identify specs that are based on the WebGL spec,
+// like the CSS Shaders spec.
+//
+bool isWebGLBasedSpec(ShShaderSpec spec);
+
+//
+// The base class used to back handles returned to the driver.
+//
+class TShHandleBase {
+public:
+ TShHandleBase();
+ virtual ~TShHandleBase();
+ virtual TCompiler* getAsCompiler() { return 0; }
+ virtual TranslatorHLSL* getAsTranslatorHLSL() { return 0; }
+
+protected:
+ // Memory allocator. Allocates and tracks memory required by the compiler.
+ // Deallocates all memory when compiler is destructed.
+ TPoolAllocator allocator;
+};
+
+//
+// The base class for the machine dependent compiler to derive from
+// for managing object code from the compile.
+//
+class TCompiler : public TShHandleBase {
+public:
+ TCompiler(ShShaderType type, ShShaderSpec spec);
+ virtual ~TCompiler();
+ virtual TCompiler* getAsCompiler() { return this; }
+
+ bool Init(const ShBuiltInResources& resources);
+ bool compile(const char* const shaderStrings[],
+ size_t numStrings,
+ int compileOptions);
+
+ // Get results of the last compilation.
+ TInfoSink& getInfoSink() { return infoSink; }
+ const TVariableInfoList& getAttribs() const { return attribs; }
+ const TVariableInfoList& getUniforms() const { return uniforms; }
+ int getMappedNameMaxLength() const;
+
+ ShHashFunction64 getHashFunction() const { return hashFunction; }
+ NameMap& getNameMap() { return nameMap; }
+ TSymbolTable& getSymbolTable() { return symbolTable; }
+
+protected:
+ ShShaderType getShaderType() const { return shaderType; }
+ ShShaderSpec getShaderSpec() const { return shaderSpec; }
+ // Initialize symbol-table with built-in symbols.
+ bool InitBuiltInSymbolTable(const ShBuiltInResources& resources);
+ // Clears the results from the previous compilation.
+ void clearResults();
+ // Return true if function recursion is detected or call depth exceeded.
+ bool detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth);
+ // Rewrites a shader's intermediate tree according to the CSS Shaders spec.
+ void rewriteCSSShader(TIntermNode* root);
+ // Returns true if the given shader does not exceed the minimum
+ // functionality mandated in GLSL 1.0 spec Appendix A.
+ bool validateLimitations(TIntermNode* root);
+ // Collect info for all attribs and uniforms.
+ void collectAttribsUniforms(TIntermNode* root);
+ // Map long variable names into shorter ones.
+ void mapLongVariableNames(TIntermNode* root);
+ // Translate to object code.
+ virtual void translate(TIntermNode* root) = 0;
+ // Returns true if, after applying the packing rules in the GLSL 1.017 spec
+ // Appendix A, section 7, the shader does not use too many uniforms.
+ bool enforcePackingRestrictions();
+ // Returns true if the shader passes the restrictions that aim to prevent timing attacks.
+ bool enforceTimingRestrictions(TIntermNode* root, bool outputGraph);
+ // Returns true if the shader does not use samplers.
+ bool enforceVertexShaderTimingRestrictions(TIntermNode* root);
+ // Returns true if the shader does not use sampler dependent values to affect control
+ // flow or in operations whose time can depend on the input values.
+ bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph);
+ // Return true if the maximum expression complexity below the limit.
+ bool limitExpressionComplexity(TIntermNode* root);
+ // Get built-in extensions with default behavior.
+ const TExtensionBehavior& getExtensionBehavior() const;
+ // Get the resources set by InitBuiltInSymbolTable
+ const ShBuiltInResources& getResources() const;
+
+ const ArrayBoundsClamper& getArrayBoundsClamper() const;
+ ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const;
+ const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
+
+private:
+ ShShaderType shaderType;
+ ShShaderSpec shaderSpec;
+
+ int maxUniformVectors;
+ int maxExpressionComplexity;
+ int maxCallStackDepth;
+
+ ShBuiltInResources compileResources;
+
+ // Built-in symbol table for the given language, spec, and resources.
+ // It is preserved from compile-to-compile.
+ TSymbolTable symbolTable;
+ // Built-in extensions with default behavior.
+ TExtensionBehavior extensionBehavior;
+ bool fragmentPrecisionHigh;
+
+ ArrayBoundsClamper arrayBoundsClamper;
+ ShArrayIndexClampingStrategy clampingStrategy;
+ BuiltInFunctionEmulator builtInFunctionEmulator;
+
+ // Results of compilation.
+ TInfoSink infoSink; // Output sink.
+ TVariableInfoList attribs; // Active attributes in the compiled shader.
+ TVariableInfoList uniforms; // Active uniforms in the compiled shader.
+
+ // Cached copy of the ref-counted singleton.
+ LongNameMap* longNameMap;
+
+ // name hashing.
+ ShHashFunction64 hashFunction;
+ NameMap nameMap;
+};
+
+//
+// This is the interface between the machine independent code
+// and the machine dependent code.
+//
+// The machine dependent code should derive from the classes
+// above. Then Construct*() and Delete*() will create and
+// destroy the machine dependent objects, which contain the
+// above machine independent information.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
+void DeleteCompiler(TCompiler*);
+
+#endif // _SHHANDLE_INCLUDED_
diff --git a/src/compiler/ShaderLang.cpp b/src/compiler/ShaderLang.cpp
new file mode 100644
index 00000000..147894e0
--- /dev/null
+++ b/src/compiler/ShaderLang.cpp
@@ -0,0 +1,363 @@
+//
+// 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.
+//
+
+//
+// Implement the top-level of interface to the compiler,
+// as defined in ShaderLang.h
+//
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/InitializeDll.h"
+#include "compiler/preprocessor/length_limits.h"
+#include "compiler/ShHandle.h"
+#include "compiler/TranslatorHLSL.h"
+
+//
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler.
+//
+
+static bool checkActiveUniformAndAttribMaxLengths(const ShHandle handle,
+ size_t expectedValue)
+{
+ size_t activeUniformLimit = 0;
+ ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
+ size_t activeAttribLimit = 0;
+ ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
+ return (expectedValue == activeUniformLimit && expectedValue == activeAttribLimit);
+}
+
+static bool checkMappedNameMaxLength(const ShHandle handle, size_t expectedValue)
+{
+ size_t mappedNameMaxLength = 0;
+ ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
+ return (expectedValue == mappedNameMaxLength);
+}
+
+static void getVariableInfo(ShShaderInfo varType,
+ const ShHandle handle,
+ int index,
+ size_t* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName)
+{
+ if (!handle || !size || !type || !name)
+ return;
+ ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
+ (varType == SH_ACTIVE_UNIFORMS));
+
+ TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return;
+
+ const TVariableInfoList& varList = varType == SH_ACTIVE_ATTRIBUTES ?
+ compiler->getAttribs() : compiler->getUniforms();
+ if (index < 0 || index >= static_cast<int>(varList.size()))
+ return;
+
+ const TVariableInfo& varInfo = varList[index];
+ if (length) *length = varInfo.name.size();
+ *size = varInfo.size;
+ *type = varInfo.type;
+
+ // This size must match that queried by
+ // SH_ACTIVE_UNIFORM_MAX_LENGTH and SH_ACTIVE_ATTRIBUTE_MAX_LENGTH
+ // in ShGetInfo, below.
+ size_t activeUniformAndAttribLength = 1 + MAX_SYMBOL_NAME_LEN;
+ ASSERT(checkActiveUniformAndAttribMaxLengths(handle, activeUniformAndAttribLength));
+ strncpy(name, varInfo.name.c_str(), activeUniformAndAttribLength);
+ name[activeUniformAndAttribLength - 1] = 0;
+ if (mappedName) {
+ // This size must match that queried by
+ // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
+ size_t maxMappedNameLength = 1 + MAX_SYMBOL_NAME_LEN;
+ ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength));
+ strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength);
+ mappedName[maxMappedNameLength - 1] = 0;
+ }
+}
+
+//
+// Driver must call this first, once, before doing any other compiler operations.
+// Subsequent calls to this function are no-op.
+//
+int ShInitialize()
+{
+ static const bool kInitialized = InitProcess();
+ return kInitialized ? 1 : 0;
+}
+
+//
+// Cleanup symbol tables
+//
+int ShFinalize()
+{
+ DetachProcess();
+ return 1;
+}
+
+//
+// Initialize built-in resources with minimum expected values.
+//
+void ShInitBuiltInResources(ShBuiltInResources* resources)
+{
+ // Constants.
+ resources->MaxVertexAttribs = 8;
+ resources->MaxVertexUniformVectors = 128;
+ resources->MaxVaryingVectors = 8;
+ resources->MaxVertexTextureImageUnits = 0;
+ resources->MaxCombinedTextureImageUnits = 8;
+ resources->MaxTextureImageUnits = 8;
+ resources->MaxFragmentUniformVectors = 16;
+ resources->MaxDrawBuffers = 1;
+
+ // Extensions.
+ resources->OES_standard_derivatives = 0;
+ resources->OES_EGL_image_external = 0;
+ resources->ARB_texture_rectangle = 0;
+ resources->EXT_draw_buffers = 0;
+ resources->EXT_frag_depth = 0;
+
+ // Disable highp precision in fragment shader by default.
+ resources->FragmentPrecisionHigh = 0;
+
+ // Disable name hashing by default.
+ resources->HashFunction = NULL;
+
+ resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
+}
+
+//
+// Driver calls these to create and destroy compiler objects.
+//
+ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
+ ShShaderOutput output,
+ const ShBuiltInResources* resources)
+{
+ TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return 0;
+
+ // Generate built-in symbol table.
+ if (!compiler->Init(*resources)) {
+ ShDestruct(base);
+ return 0;
+ }
+
+ return reinterpret_cast<void*>(base);
+}
+
+void ShDestruct(ShHandle handle)
+{
+ if (handle == 0)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+
+ if (base->getAsCompiler())
+ DeleteCompiler(base->getAsCompiler());
+}
+
+//
+// Do an actual compile on the given strings. The result is left
+// in the given compile object.
+//
+// Return: The return value of ShCompile is really boolean, indicating
+// success or failure.
+//
+int ShCompile(
+ const ShHandle handle,
+ const char* const shaderStrings[],
+ size_t numStrings,
+ int compileOptions)
+{
+ if (handle == 0)
+ return 0;
+
+ TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return 0;
+
+ bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
+ return success ? 1 : 0;
+}
+
+void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params)
+{
+ if (!handle || !params)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ switch(pname)
+ {
+ case SH_INFO_LOG_LENGTH:
+ *params = compiler->getInfoSink().info.size() + 1;
+ break;
+ case SH_OBJECT_CODE_LENGTH:
+ *params = compiler->getInfoSink().obj.size() + 1;
+ break;
+ case SH_ACTIVE_UNIFORMS:
+ *params = compiler->getUniforms().size();
+ break;
+ case SH_ACTIVE_UNIFORM_MAX_LENGTH:
+ *params = 1 + MAX_SYMBOL_NAME_LEN;
+ break;
+ case SH_ACTIVE_ATTRIBUTES:
+ *params = compiler->getAttribs().size();
+ break;
+ case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = 1 + MAX_SYMBOL_NAME_LEN;
+ break;
+ case SH_MAPPED_NAME_MAX_LENGTH:
+ // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
+ // handle array and struct dereferences.
+ *params = 1 + MAX_SYMBOL_NAME_LEN;
+ break;
+ case SH_NAME_MAX_LENGTH:
+ *params = 1 + MAX_SYMBOL_NAME_LEN;
+ break;
+ case SH_HASHED_NAME_MAX_LENGTH:
+ if (compiler->getHashFunction() == NULL) {
+ *params = 0;
+ } else {
+ // 64 bits hashing output requires 16 bytes for hex
+ // representation.
+ const char HashedNamePrefix[] = HASHED_NAME_PREFIX;
+ *params = 16 + sizeof(HashedNamePrefix);
+ }
+ break;
+ case SH_HASHED_NAMES_COUNT:
+ *params = compiler->getNameMap().size();
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+//
+// Return any compiler log of messages for the application.
+//
+void ShGetInfoLog(const ShHandle handle, char* infoLog)
+{
+ if (!handle || !infoLog)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ TInfoSink& infoSink = compiler->getInfoSink();
+ strcpy(infoLog, infoSink.info.c_str());
+}
+
+//
+// Return any object code.
+//
+void ShGetObjectCode(const ShHandle handle, char* objCode)
+{
+ if (!handle || !objCode)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ TInfoSink& infoSink = compiler->getInfoSink();
+ strcpy(objCode, infoSink.obj.c_str());
+}
+
+void ShGetActiveAttrib(const ShHandle handle,
+ int index,
+ size_t* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName)
+{
+ getVariableInfo(SH_ACTIVE_ATTRIBUTES,
+ handle, index, length, size, type, name, mappedName);
+}
+
+void ShGetActiveUniform(const ShHandle handle,
+ int index,
+ size_t* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName)
+{
+ getVariableInfo(SH_ACTIVE_UNIFORMS,
+ handle, index, length, size, type, name, mappedName);
+}
+
+void ShGetNameHashingEntry(const ShHandle handle,
+ int index,
+ char* name,
+ char* hashedName)
+{
+ if (!handle || !name || !hashedName || index < 0)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ const NameMap& nameMap = compiler->getNameMap();
+ if (index >= static_cast<int>(nameMap.size()))
+ return;
+
+ NameMap::const_iterator it = nameMap.begin();
+ for (int i = 0; i < index; ++i)
+ ++it;
+
+ size_t len = it->first.length() + 1;
+ size_t max_len = 0;
+ ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len);
+ if (len > max_len) {
+ ASSERT(false);
+ len = max_len;
+ }
+ strncpy(name, it->first.c_str(), len);
+ // To be on the safe side in case the source is longer than expected.
+ name[len - 1] = '\0';
+
+ len = it->second.length() + 1;
+ max_len = 0;
+ ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len);
+ if (len > max_len) {
+ ASSERT(false);
+ len = max_len;
+ }
+ strncpy(hashedName, it->second.c_str(), len);
+ // To be on the safe side in case the source is longer than expected.
+ hashedName[len - 1] = '\0';
+}
+
+void ShGetInfoPointer(const ShHandle handle, ShShaderInfo pname, void** params)
+{
+ if (!handle || !params)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TranslatorHLSL* translator = base->getAsTranslatorHLSL();
+ if (!translator) return;
+
+ switch(pname)
+ {
+ case SH_ACTIVE_UNIFORMS_ARRAY:
+ *params = (void*)&translator->getUniforms();
+ break;
+ default: UNREACHABLE();
+ }
+}
diff --git a/src/compiler/SymbolTable.cpp b/src/compiler/SymbolTable.cpp
new file mode 100644
index 00000000..51180aff
--- /dev/null
+++ b/src/compiler/SymbolTable.cpp
@@ -0,0 +1,208 @@
+//
+// 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.
+//
+
+//
+// Symbol table for parsing. Most functionaliy and main ideas
+// are documented in the header file.
+//
+
+#if defined(_MSC_VER)
+#pragma warning(disable: 4718)
+#endif
+
+#include "compiler/SymbolTable.h"
+
+#include <stdio.h>
+#include <algorithm>
+#include <climits>
+
+TType::TType(const TPublicType &p) :
+ type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize), structure(0)
+{
+ if (p.userDef)
+ structure = p.userDef->getStruct();
+}
+
+//
+// Recursively generate mangled names.
+//
+TString TType::buildMangledName() const
+{
+ TString mangledName;
+ if (isMatrix())
+ mangledName += 'm';
+ else if (isVector())
+ mangledName += 'v';
+
+ switch (type) {
+ case EbtFloat: mangledName += 'f'; break;
+ case EbtInt: mangledName += 'i'; break;
+ case EbtBool: mangledName += 'b'; break;
+ case EbtSampler2D: mangledName += "s2"; break;
+ case EbtSamplerCube: mangledName += "sC"; break;
+ case EbtStruct: mangledName += structure->mangledName(); break;
+ default: break;
+ }
+
+ mangledName += static_cast<char>('0' + getNominalSize());
+ if (isArray()) {
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", arraySize);
+ mangledName += '[';
+ mangledName += buf;
+ mangledName += ']';
+ }
+ return mangledName;
+}
+
+size_t TType::getObjectSize() const
+{
+ size_t totalSize = 0;
+
+ if (getBasicType() == EbtStruct)
+ totalSize = structure->objectSize();
+ else if (matrix)
+ totalSize = size * size;
+ else
+ totalSize = size;
+
+ if (isArray()) {
+ size_t arraySize = getArraySize();
+ if (arraySize > INT_MAX / totalSize)
+ totalSize = INT_MAX;
+ else
+ totalSize *= arraySize;
+ }
+
+ return totalSize;
+}
+
+bool TStructure::containsArrays() const
+{
+ for (size_t i = 0; i < mFields->size(); ++i) {
+ const TType* fieldType = (*mFields)[i]->type();
+ if (fieldType->isArray() || fieldType->isStructureContainingArrays())
+ return true;
+ }
+ return false;
+}
+
+TString TStructure::buildMangledName() const
+{
+ TString mangledName("struct-");
+ mangledName += *mName;
+ for (size_t i = 0; i < mFields->size(); ++i) {
+ mangledName += '-';
+ mangledName += (*mFields)[i]->type()->getMangledName();
+ }
+ return mangledName;
+}
+
+size_t TStructure::calculateObjectSize() const
+{
+ size_t size = 0;
+ for (size_t i = 0; i < mFields->size(); ++i) {
+ size_t fieldSize = (*mFields)[i]->type()->getObjectSize();
+ if (fieldSize > INT_MAX - size)
+ size = INT_MAX;
+ else
+ size += fieldSize;
+ }
+ return size;
+}
+
+int TStructure::calculateDeepestNesting() const
+{
+ int maxNesting = 0;
+ for (size_t i = 0; i < mFields->size(); ++i) {
+ maxNesting = std::max(maxNesting, (*mFields)[i]->type()->getDeepestStructNesting());
+ }
+ return 1 + maxNesting;
+}
+
+//
+// Dump functions.
+//
+
+void TVariable::dump(TInfoSink& infoSink) const
+{
+ infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString();
+ if (type.isArray()) {
+ infoSink.debug << "[0]";
+ }
+ infoSink.debug << "\n";
+}
+
+void TFunction::dump(TInfoSink &infoSink) const
+{
+ infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n";
+}
+
+void TSymbolTableLevel::dump(TInfoSink &infoSink) const
+{
+ tLevel::const_iterator it;
+ for (it = level.begin(); it != level.end(); ++it)
+ (*it).second->dump(infoSink);
+}
+
+void TSymbolTable::dump(TInfoSink &infoSink) const
+{
+ for (int level = currentLevel(); level >= 0; --level) {
+ infoSink.debug << "LEVEL " << level << "\n";
+ table[level]->dump(infoSink);
+ }
+}
+
+//
+// Functions have buried pointers to delete.
+//
+TFunction::~TFunction()
+{
+ for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
+ delete (*i).type;
+}
+
+//
+// Symbol table levels are a map of pointers to symbols that have to be deleted.
+//
+TSymbolTableLevel::~TSymbolTableLevel()
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
+ delete (*it).second;
+}
+
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in operation. This is a low
+// performance operation, and only intended for symbol tables that
+// live across a large number of compiles.
+//
+void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
+{
+ tLevel::iterator it;
+ for (it = level.begin(); it != level.end(); ++it) {
+ if ((*it).second->isFunction()) {
+ TFunction* function = static_cast<TFunction*>((*it).second);
+ if (function->getName() == name)
+ function->relateToOperator(op);
+ }
+ }
+}
+
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in extension. This is a low
+// performance operation, and only intended for symbol tables that
+// live across a large number of compiles.
+//
+void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext)
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it) {
+ TSymbol* symbol = it->second;
+ if (symbol->getName() == name)
+ symbol->relateToExtension(ext);
+ }
+}
diff --git a/src/compiler/SymbolTable.h b/src/compiler/SymbolTable.h
new file mode 100644
index 00000000..f9a7948a
--- /dev/null
+++ b/src/compiler/SymbolTable.h
@@ -0,0 +1,390 @@
+//
+// 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.
+//
+
+#ifndef _SYMBOL_TABLE_INCLUDED_
+#define _SYMBOL_TABLE_INCLUDED_
+
+//
+// Symbol table for parsing. Has these design characteristics:
+//
+// * Same symbol table can be used to compile many shaders, to preserve
+// effort of creating and loading with the large numbers of built-in
+// symbols.
+//
+// * Name mangling will be used to give each function a unique name
+// so that symbol table lookups are never ambiguous. This allows
+// a simpler symbol table structure.
+//
+// * Pushing and popping of scope, so symbol table will really be a stack
+// of symbol tables. Searched from the top, with new inserts going into
+// the top.
+//
+// * Constants: Compile time constant symbols will keep their values
+// in the symbol table. The parser can substitute constants at parse
+// time, including doing constant folding and constant propagation.
+//
+// * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
+// are tracked in the intermediate representation, not the symbol table.
+//
+
+#include <assert.h>
+
+#include "common/angleutils.h"
+#include "compiler/InfoSink.h"
+#include "compiler/intermediate.h"
+
+//
+// Symbol base class. (Can build functions or variables out of these...)
+//
+class TSymbol {
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TSymbol(const TString *n) : name(n) { }
+ virtual ~TSymbol() { /* don't delete name, it's from the pool */ }
+
+ const TString& getName() const { return *name; }
+ virtual const TString& getMangledName() const { return getName(); }
+ virtual bool isFunction() const { return false; }
+ virtual bool isVariable() const { return false; }
+ void setUniqueId(int id) { uniqueId = id; }
+ int getUniqueId() const { return uniqueId; }
+ virtual void dump(TInfoSink &infoSink) const = 0;
+ void relateToExtension(const TString& ext) { extension = ext; }
+ const TString& getExtension() const { return extension; }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(TSymbol);
+
+ const TString *name;
+ unsigned int uniqueId; // For real comparing during code generation
+ TString extension;
+};
+
+//
+// Variable class, meaning a symbol that's not a function.
+//
+// There could be a separate class heirarchy for Constant variables;
+// Only one of int, bool, or float, (or none) is correct for
+// any particular use, but it's easy to do this way, and doesn't
+// seem worth having separate classes, and "getConst" can't simply return
+// different values for different types polymorphically, so this is
+// just simple and pragmatic.
+//
+class TVariable : public TSymbol {
+public:
+ TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0) { }
+ virtual ~TVariable() { }
+ virtual bool isVariable() const { return true; }
+ TType& getType() { return type; }
+ const TType& getType() const { return type; }
+ bool isUserType() const { return userType; }
+ void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); }
+
+ virtual void dump(TInfoSink &infoSink) const;
+
+ ConstantUnion* getConstPointer()
+ {
+ if (!unionArray)
+ unionArray = new ConstantUnion[type.getObjectSize()];
+
+ return unionArray;
+ }
+
+ ConstantUnion* getConstPointer() const { return unionArray; }
+
+ void shareConstPointer( ConstantUnion *constArray)
+ {
+ if (unionArray == constArray)
+ return;
+
+ delete[] unionArray;
+ unionArray = constArray;
+ }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(TVariable);
+
+ TType type;
+ bool userType;
+ // we are assuming that Pool Allocator will free the memory allocated to unionArray
+ // when this object is destroyed
+ ConstantUnion *unionArray;
+};
+
+//
+// The function sub-class of symbols and the parser will need to
+// share this definition of a function parameter.
+//
+struct TParameter {
+ TString *name;
+ TType* type;
+};
+
+//
+// The function sub-class of a symbol.
+//
+class TFunction : public TSymbol {
+public:
+ TFunction(TOperator o) :
+ TSymbol(0),
+ returnType(TType(EbtVoid, EbpUndefined)),
+ op(o),
+ defined(false) { }
+ TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) :
+ TSymbol(name),
+ returnType(retType),
+ mangledName(TFunction::mangleName(*name)),
+ op(tOp),
+ defined(false) { }
+ virtual ~TFunction();
+ virtual bool isFunction() const { return true; }
+
+ static TString mangleName(const TString& name) { return name + '('; }
+ static TString unmangleName(const TString& mangledName)
+ {
+ return TString(mangledName.c_str(), mangledName.find_first_of('('));
+ }
+
+ void addParameter(TParameter& p)
+ {
+ parameters.push_back(p);
+ mangledName = mangledName + p.type->getMangledName();
+ }
+
+ const TString& getMangledName() const { return mangledName; }
+ const TType& getReturnType() const { return returnType; }
+
+ void relateToOperator(TOperator o) { op = o; }
+ TOperator getBuiltInOp() const { return op; }
+
+ void setDefined() { defined = true; }
+ bool isDefined() { return defined; }
+
+ size_t getParamCount() const { return parameters.size(); }
+ const TParameter& getParam(size_t i) const { return parameters[i]; }
+
+ virtual void dump(TInfoSink &infoSink) const;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(TFunction);
+
+ typedef TVector<TParameter> TParamList;
+ TParamList parameters;
+ TType returnType;
+ TString mangledName;
+ TOperator op;
+ bool defined;
+};
+
+
+class TSymbolTableLevel {
+public:
+ typedef TMap<TString, TSymbol*> tLevel;
+ typedef tLevel::const_iterator const_iterator;
+ typedef const tLevel::value_type tLevelPair;
+ typedef std::pair<tLevel::iterator, bool> tInsertResult;
+
+ POOL_ALLOCATOR_NEW_DELETE();
+ TSymbolTableLevel() { }
+ ~TSymbolTableLevel();
+
+ bool insert(const TString &name, TSymbol &symbol)
+ {
+ //
+ // returning true means symbol was added to the table
+ //
+ tInsertResult result;
+ result = level.insert(tLevelPair(name, &symbol));
+
+ return result.second;
+ }
+
+ bool insert(TSymbol &symbol)
+ {
+ return insert(symbol.getMangledName(), symbol);
+ }
+
+ TSymbol* find(const TString& name) const
+ {
+ tLevel::const_iterator it = level.find(name);
+ if (it == level.end())
+ return 0;
+ else
+ return (*it).second;
+ }
+
+ const_iterator begin() const
+ {
+ return level.begin();
+ }
+
+ const_iterator end() const
+ {
+ return level.end();
+ }
+
+ void relateToOperator(const char* name, TOperator op);
+ void relateToExtension(const char* name, const TString& ext);
+ void dump(TInfoSink &infoSink) const;
+
+protected:
+ tLevel level;
+};
+
+class TSymbolTable {
+public:
+ TSymbolTable() : uniqueId(0)
+ {
+ //
+ // The symbol table cannot be used until push() is called, but
+ // the lack of an initial call to push() can be used to detect
+ // that the symbol table has not been preloaded with built-ins.
+ //
+ }
+
+ ~TSymbolTable()
+ {
+ // level 0 is always built In symbols, so we never pop that out
+ while (table.size() > 1)
+ pop();
+ }
+
+ //
+ // When the symbol table is initialized with the built-ins, there should
+ // 'push' calls, so that built-ins are at level 0 and the shader
+ // globals are at level 1.
+ //
+ bool isEmpty() { return table.size() == 0; }
+ bool atBuiltInLevel() { return table.size() == 1; }
+ bool atGlobalLevel() { return table.size() <= 2; }
+ void push()
+ {
+ table.push_back(new TSymbolTableLevel);
+ precisionStack.push_back( PrecisionStackLevel() );
+ }
+
+ void pop()
+ {
+ delete table[currentLevel()];
+ table.pop_back();
+ precisionStack.pop_back();
+ }
+
+ bool insert(TSymbol& symbol)
+ {
+ symbol.setUniqueId(++uniqueId);
+ return table[currentLevel()]->insert(symbol);
+ }
+
+ bool insertConstInt(const char *name, int value)
+ {
+ TVariable *constant = new TVariable(NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
+ constant->getConstPointer()->setIConst(value);
+ return insert(*constant);
+ }
+
+ bool insertBuiltIn(TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0)
+ {
+ TFunction *function = new TFunction(NewPoolTString(name), *rvalue);
+
+ TParameter param1 = {NULL, ptype1};
+ function->addParameter(param1);
+
+ if(ptype2)
+ {
+ TParameter param2 = {NULL, ptype2};
+ function->addParameter(param2);
+ }
+
+ if(ptype3)
+ {
+ TParameter param3 = {NULL, ptype3};
+ function->addParameter(param3);
+ }
+
+ return insert(*function);
+ }
+
+ TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0)
+ {
+ int level = currentLevel();
+ TSymbol* symbol;
+ do {
+ symbol = table[level]->find(name);
+ --level;
+ } while (symbol == 0 && level >= 0);
+ level++;
+ if (builtIn)
+ *builtIn = level == 0;
+ if (sameScope)
+ *sameScope = level == currentLevel();
+ return symbol;
+ }
+
+ TSymbol *findBuiltIn(const TString &name)
+ {
+ return table[0]->find(name);
+ }
+
+ TSymbolTableLevel* getGlobalLevel() {
+ assert(table.size() >= 2);
+ return table[1];
+ }
+
+ TSymbolTableLevel* getOuterLevel() {
+ assert(table.size() >= 2);
+ return table[currentLevel() - 1];
+ }
+
+ void relateToOperator(const char* name, TOperator op) {
+ table[0]->relateToOperator(name, op);
+ }
+ void relateToExtension(const char* name, const TString& ext) {
+ table[0]->relateToExtension(name, ext);
+ }
+ int getMaxSymbolId() { return uniqueId; }
+ void dump(TInfoSink &infoSink) const;
+
+ bool setDefaultPrecision( const TPublicType& type, TPrecision prec ){
+ if (IsSampler(type.type))
+ return true; // Skip sampler types for the time being
+ if (type.type != EbtFloat && type.type != EbtInt)
+ return false; // Only set default precision for int/float
+ if (type.size != 1 || type.matrix || type.array)
+ return false; // Not allowed to set for aggregate types
+ int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
+ precisionStack[indexOfLastElement][type.type] = prec; // Uses map operator [], overwrites the current value
+ return true;
+ }
+
+ // Searches down the precisionStack for a precision qualifier for the specified TBasicType
+ TPrecision getDefaultPrecision( TBasicType type){
+ if( type != EbtFloat && type != EbtInt ) return EbpUndefined;
+ int level = static_cast<int>(precisionStack.size()) - 1;
+ assert( level >= 0); // Just to be safe. Should not happen.
+ PrecisionStackLevel::iterator it;
+ TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this?
+ while( level >= 0 ){
+ it = precisionStack[level].find( type );
+ if( it != precisionStack[level].end() ){
+ prec = (*it).second;
+ break;
+ }
+ level--;
+ }
+ return prec;
+ }
+
+protected:
+ int currentLevel() const { return static_cast<int>(table.size()) - 1; }
+
+ std::vector<TSymbolTableLevel*> table;
+ typedef std::map< TBasicType, TPrecision > PrecisionStackLevel;
+ std::vector< PrecisionStackLevel > precisionStack;
+ int uniqueId; // for unique identification in code generation
+};
+
+#endif // _SYMBOL_TABLE_INCLUDED_
diff --git a/src/compiler/TranslatorESSL.cpp b/src/compiler/TranslatorESSL.cpp
new file mode 100644
index 00000000..2900f8a8
--- /dev/null
+++ b/src/compiler/TranslatorESSL.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorESSL.h"
+
+#include "compiler/OutputESSL.h"
+
+TranslatorESSL::TranslatorESSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec) {
+}
+
+void TranslatorESSL::translate(TIntermNode* root) {
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ // Write built-in extension behaviors.
+ writeExtensionBehavior();
+
+ // Write emulated built-in functions if needed.
+ getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
+ sink, getShaderType() == SH_FRAGMENT_SHADER);
+
+ // Write array bounds clamping emulation if needed.
+ getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
+
+ // Write translated shader.
+ TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable());
+ root->traverse(&outputESSL);
+}
+
+void TranslatorESSL::writeExtensionBehavior() {
+ TInfoSinkBase& sink = getInfoSink().obj;
+ const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
+ iter != extensionBehavior.end(); ++iter) {
+ if (iter->second != EBhUndefined) {
+ sink << "#extension " << iter->first << " : "
+ << getBehaviorString(iter->second) << "\n";
+ }
+ }
+}
diff --git a/src/compiler/TranslatorESSL.h b/src/compiler/TranslatorESSL.h
new file mode 100644
index 00000000..a1196bd0
--- /dev/null
+++ b/src/compiler/TranslatorESSL.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORESSL_H_
+#define COMPILER_TRANSLATORESSL_H_
+
+#include "compiler/ShHandle.h"
+
+class TranslatorESSL : public TCompiler {
+public:
+ TranslatorESSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+
+private:
+ void writeExtensionBehavior();
+};
+
+#endif // COMPILER_TRANSLATORESSL_H_
diff --git a/src/compiler/TranslatorGLSL.cpp b/src/compiler/TranslatorGLSL.cpp
new file mode 100644
index 00000000..7ca4341d
--- /dev/null
+++ b/src/compiler/TranslatorGLSL.cpp
@@ -0,0 +1,44 @@
+//
+// 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.
+//
+
+#include "compiler/TranslatorGLSL.h"
+
+#include "compiler/OutputGLSL.h"
+#include "compiler/VersionGLSL.h"
+
+static void writeVersion(ShShaderType type, TIntermNode* root,
+ TInfoSinkBase& sink) {
+ TVersionGLSL versionGLSL(type);
+ root->traverse(&versionGLSL);
+ int version = versionGLSL.getVersion();
+ // We need to write version directive only if it is greater than 110.
+ // If there is no version directive in the shader, 110 is implied.
+ if (version > 110) {
+ sink << "#version " << version << "\n";
+ }
+}
+
+TranslatorGLSL::TranslatorGLSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec) {
+}
+
+void TranslatorGLSL::translate(TIntermNode* root) {
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ // Write GLSL version.
+ writeVersion(getShaderType(), root, sink);
+
+ // Write emulated built-in functions if needed.
+ getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
+ sink, false);
+
+ // Write array bounds clamping emulation if needed.
+ getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
+
+ // Write translated shader.
+ TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable());
+ root->traverse(&outputGLSL);
+}
diff --git a/src/compiler/TranslatorGLSL.h b/src/compiler/TranslatorGLSL.h
new file mode 100644
index 00000000..c2ce06d1
--- /dev/null
+++ b/src/compiler/TranslatorGLSL.h
@@ -0,0 +1,20 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_TRANSLATORGLSL_H_
+#define COMPILER_TRANSLATORGLSL_H_
+
+#include "compiler/ShHandle.h"
+
+class TranslatorGLSL : public TCompiler {
+public:
+ TranslatorGLSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+};
+
+#endif // COMPILER_TRANSLATORGLSL_H_
diff --git a/src/compiler/TranslatorHLSL.cpp b/src/compiler/TranslatorHLSL.cpp
new file mode 100644
index 00000000..37408a07
--- /dev/null
+++ b/src/compiler/TranslatorHLSL.cpp
@@ -0,0 +1,24 @@
+//
+// 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.
+//
+
+#include "compiler/TranslatorHLSL.h"
+
+#include "compiler/InitializeParseContext.h"
+#include "compiler/OutputHLSL.h"
+
+TranslatorHLSL::TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+ : TCompiler(type, spec), mOutputType(output)
+{
+}
+
+void TranslatorHLSL::translate(TIntermNode *root)
+{
+ TParseContext& parseContext = *GetGlobalParseContext();
+ sh::OutputHLSL outputHLSL(parseContext, getResources(), mOutputType);
+
+ outputHLSL.output();
+ mActiveUniforms = outputHLSL.getUniforms();
+}
diff --git a/src/compiler/TranslatorHLSL.h b/src/compiler/TranslatorHLSL.h
new file mode 100644
index 00000000..9550e15e
--- /dev/null
+++ b/src/compiler/TranslatorHLSL.h
@@ -0,0 +1,27 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_TRANSLATORHLSL_H_
+#define COMPILER_TRANSLATORHLSL_H_
+
+#include "compiler/ShHandle.h"
+#include "compiler/Uniform.h"
+
+class TranslatorHLSL : public TCompiler {
+public:
+ TranslatorHLSL(ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
+
+ virtual TranslatorHLSL *getAsTranslatorHLSL() { return this; }
+ const sh::ActiveUniforms &getUniforms() { return mActiveUniforms; }
+
+protected:
+ virtual void translate(TIntermNode* root);
+
+ sh::ActiveUniforms mActiveUniforms;
+ ShShaderOutput mOutputType;
+};
+
+#endif // COMPILER_TRANSLATORHLSL_H_
diff --git a/src/compiler/Types.h b/src/compiler/Types.h
new file mode 100644
index 00000000..505fa8e3
--- /dev/null
+++ b/src/compiler/Types.h
@@ -0,0 +1,307 @@
+//
+// 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.
+//
+
+#ifndef _TYPES_INCLUDED
+#define _TYPES_INCLUDED
+
+#include "common/angleutils.h"
+
+#include "compiler/BaseTypes.h"
+#include "compiler/Common.h"
+#include "compiler/debug.h"
+
+struct TPublicType;
+class TType;
+
+class TField
+{
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TField(TType* type, TString* name) : mType(type), mName(name) {}
+
+ // TODO(alokp): We should only return const type.
+ // Fix it by tweaking grammar.
+ TType* type() { return mType; }
+ const TType* type() const { return mType; }
+
+ const TString& name() const { return *mName; }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(TField);
+ TType* mType;
+ TString* mName;
+};
+
+typedef TVector<TField*> TFieldList;
+inline TFieldList* NewPoolTFieldList()
+{
+ void* memory = GetGlobalPoolAllocator()->allocate(sizeof(TFieldList));
+ return new(memory) TFieldList;
+}
+
+class TStructure
+{
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TStructure(TString* name, TFieldList* fields)
+ : mName(name),
+ mFields(fields),
+ mObjectSize(0),
+ mDeepestNesting(0) {
+ }
+
+ const TString& name() const { return *mName; }
+ const TFieldList& fields() const { return *mFields; }
+
+ const TString& mangledName() const {
+ if (mMangledName.empty())
+ mMangledName = buildMangledName();
+ return mMangledName;
+ }
+ size_t objectSize() const {
+ if (mObjectSize == 0)
+ mObjectSize = calculateObjectSize();
+ return mObjectSize;
+ };
+ int deepestNesting() const {
+ if (mDeepestNesting == 0)
+ mDeepestNesting = calculateDeepestNesting();
+ return mDeepestNesting;
+ }
+ bool containsArrays() const;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(TStructure);
+ TString buildMangledName() const;
+ size_t calculateObjectSize() const;
+ int calculateDeepestNesting() const;
+
+ TString* mName;
+ TFieldList* mFields;
+
+ mutable TString mMangledName;
+ mutable size_t mObjectSize;
+ mutable int mDeepestNesting;
+};
+
+//
+// Base class for things that have a type.
+//
+class TType
+{
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TType() {}
+ TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) :
+ type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0), structure(0)
+ {
+ }
+ explicit TType(const TPublicType &p);
+ TType(TStructure* userDef, TPrecision p = EbpUndefined) :
+ type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0), structure(userDef)
+ {
+ }
+
+ TBasicType getBasicType() const { return type; }
+ void setBasicType(TBasicType t) { type = t; }
+
+ TPrecision getPrecision() const { return precision; }
+ void setPrecision(TPrecision p) { precision = p; }
+
+ TQualifier getQualifier() const { return qualifier; }
+ void setQualifier(TQualifier q) { qualifier = q; }
+
+ // One-dimensional size of single instance type
+ int getNominalSize() const { return size; }
+ void setNominalSize(int s) { size = s; }
+ // Full size of single instance of type
+ size_t getObjectSize() const;
+
+ int elementRegisterCount() const
+ {
+ if (structure)
+ {
+ const TFieldList &fields = getStruct()->fields();
+ int registerCount = 0;
+
+ for (size_t i = 0; i < fields.size(); i++)
+ {
+ registerCount += fields[i]->type()->totalRegisterCount();
+ }
+
+ return registerCount;
+ }
+ else if (isMatrix())
+ {
+ return getNominalSize();
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ int totalRegisterCount() const
+ {
+ if (array)
+ {
+ return arraySize * elementRegisterCount();
+ }
+ else
+ {
+ return elementRegisterCount();
+ }
+ }
+
+ bool isMatrix() const { return matrix ? true : false; }
+ void setMatrix(bool m) { matrix = m; }
+
+ bool isArray() const { return array ? true : false; }
+ int getArraySize() const { return arraySize; }
+ void setArraySize(int s) { array = true; arraySize = s; }
+ void clearArrayness() { array = false; arraySize = 0; }
+
+ bool isVector() const { return size > 1 && !matrix; }
+ bool isScalar() const { return size == 1 && !matrix && !structure; }
+
+ TStructure* getStruct() const { return structure; }
+ void setStruct(TStructure* s) { structure = s; }
+
+ const TString& getMangledName() const {
+ if (mangled.empty()) {
+ mangled = buildMangledName();
+ mangled += ';';
+ }
+ return mangled;
+ }
+
+ bool sameElementType(const TType& right) const {
+ return type == right.type &&
+ size == right.size &&
+ matrix == right.matrix &&
+ structure == right.structure;
+ }
+ bool operator==(const TType& right) const {
+ return type == right.type &&
+ size == right.size &&
+ matrix == right.matrix &&
+ array == right.array && (!array || arraySize == right.arraySize) &&
+ structure == right.structure;
+ // don't check the qualifier, it's not ever what's being sought after
+ }
+ bool operator!=(const TType& right) const {
+ return !operator==(right);
+ }
+ bool operator<(const TType& right) const {
+ if (type != right.type) return type < right.type;
+ if (size != right.size) return size < right.size;
+ if (matrix != right.matrix) return matrix < right.matrix;
+ if (array != right.array) return array < right.array;
+ if (arraySize != right.arraySize) return arraySize < right.arraySize;
+ if (structure != right.structure) return structure < right.structure;
+
+ return false;
+ }
+
+ const char* getBasicString() const { return ::getBasicString(type); }
+ const char* getPrecisionString() const { return ::getPrecisionString(precision); }
+ const char* getQualifierString() const { return ::getQualifierString(qualifier); }
+ TString getCompleteString() const;
+
+ // If this type is a struct, returns the deepest struct nesting of
+ // any field in the struct. For example:
+ // struct nesting1 {
+ // vec4 position;
+ // };
+ // struct nesting2 {
+ // nesting1 field1;
+ // vec4 field2;
+ // };
+ // For type "nesting2", this method would return 2 -- the number
+ // of structures through which indirection must occur to reach the
+ // deepest field (nesting2.field1.position).
+ int getDeepestStructNesting() const {
+ return structure ? structure->deepestNesting() : 0;
+ }
+
+ bool isStructureContainingArrays() const {
+ return structure ? structure->containsArrays() : false;
+ }
+
+private:
+ TString buildMangledName() const;
+
+ TBasicType type : 6;
+ TPrecision precision;
+ TQualifier qualifier : 7;
+ int size : 8; // size of vector or matrix, not size of array
+ unsigned int matrix : 1;
+ unsigned int array : 1;
+ int arraySize;
+
+ TStructure* structure; // 0 unless this is a struct
+
+ mutable TString mangled;
+};
+
+//
+// This is a workaround for a problem with the yacc stack, It can't have
+// types that it thinks have non-trivial constructors. It should
+// just be used while recognizing the grammar, not anything else. Pointers
+// could be used, but also trying to avoid lots of memory management overhead.
+//
+// Not as bad as it looks, there is no actual assumption that the fields
+// match up or are name the same or anything like that.
+//
+struct TPublicType
+{
+ TBasicType type;
+ TQualifier qualifier;
+ TPrecision precision;
+ int size; // size of vector or matrix, not size of array
+ bool matrix;
+ bool array;
+ int arraySize;
+ TType* userDef;
+ TSourceLoc line;
+
+ void setBasic(TBasicType bt, TQualifier q, const TSourceLoc& ln)
+ {
+ type = bt;
+ qualifier = q;
+ precision = EbpUndefined;
+ size = 1;
+ matrix = false;
+ array = false;
+ arraySize = 0;
+ userDef = 0;
+ line = ln;
+ }
+
+ void setAggregate(int s, bool m = false)
+ {
+ size = s;
+ matrix = m;
+ }
+
+ void setArray(bool a, int s = 0)
+ {
+ array = a;
+ arraySize = s;
+ }
+
+ bool isStructureContainingArrays() const
+ {
+ if (!userDef)
+ {
+ return false;
+ }
+
+ return userDef->isStructureContainingArrays();
+ }
+};
+
+#endif // _TYPES_INCLUDED_
diff --git a/src/compiler/UnfoldShortCircuit.cpp b/src/compiler/UnfoldShortCircuit.cpp
new file mode 100644
index 00000000..47f0afca
--- /dev/null
+++ b/src/compiler/UnfoldShortCircuit.cpp
@@ -0,0 +1,176 @@
+//
+// 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.
+//
+// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements.
+// The results are assigned to s# temporaries, which are used by the main translator instead of
+// the original expression.
+//
+
+#include "compiler/UnfoldShortCircuit.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/OutputHLSL.h"
+
+namespace sh
+{
+UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL)
+{
+ mTemporaryIndex = 0;
+}
+
+void UnfoldShortCircuit::traverse(TIntermNode *node)
+{
+ int rewindIndex = mTemporaryIndex;
+ node->traverse(this);
+ mTemporaryIndex = rewindIndex;
+}
+
+bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase &out = mOutputHLSL->getBodyStream();
+
+ switch (node->getOp())
+ {
+ case EOpLogicalOr:
+ // "x || y" is equivalent to "x ? true : y", which unfolds to "bool s; if(x) s = true; else s = y;",
+ // and then further simplifies down to "bool s = x; if(!s) s = y;".
+ {
+ int i = mTemporaryIndex;
+
+ out << "bool s" << i << ";\n";
+
+ out << "{\n";
+
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(this);
+ out << "s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(mOutputHLSL);
+ out << ";\n";
+ out << "if(!s" << i << ")\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ out << "}\n";
+
+ mTemporaryIndex = i + 1;
+ }
+ return false;
+ case EOpLogicalAnd:
+ // "x && y" is equivalent to "x ? y : false", which unfolds to "bool s; if(x) s = y; else s = false;",
+ // and then further simplifies down to "bool s = x; if(s) s = y;".
+ {
+ int i = mTemporaryIndex;
+
+ out << "bool s" << i << ";\n";
+
+ out << "{\n";
+
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(this);
+ out << "s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getLeft()->traverse(mOutputHLSL);
+ out << ";\n";
+ out << "if(s" << i << ")\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getRight()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ out << "}\n";
+
+ mTemporaryIndex = i + 1;
+ }
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = mOutputHLSL->getBodyStream();
+
+ // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;"
+ if (node->usesTernaryOperator())
+ {
+ int i = mTemporaryIndex;
+
+ out << mOutputHLSL->typeString(node->getType()) << " s" << i << ";\n";
+
+ out << "{\n";
+
+ mTemporaryIndex = i + 1;
+ node->getCondition()->traverse(this);
+ out << "if(";
+ mTemporaryIndex = i + 1;
+ node->getCondition()->traverse(mOutputHLSL);
+ out << ")\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getTrueBlock()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getTrueBlock()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n"
+ "else\n"
+ "{\n";
+ mTemporaryIndex = i + 1;
+ node->getFalseBlock()->traverse(this);
+ out << " s" << i << " = ";
+ mTemporaryIndex = i + 1;
+ node->getFalseBlock()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ out << "}\n";
+
+ mTemporaryIndex = i + 1;
+ }
+
+ return false;
+}
+
+bool UnfoldShortCircuit::visitLoop(Visit visit, TIntermLoop *node)
+{
+ int rewindIndex = mTemporaryIndex;
+
+ if (node->getInit())
+ {
+ node->getInit()->traverse(this);
+ }
+
+ if (node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+ }
+
+ if (node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+ }
+
+ mTemporaryIndex = rewindIndex;
+
+ return false;
+}
+
+int UnfoldShortCircuit::getNextTemporaryIndex()
+{
+ return mTemporaryIndex++;
+}
+}
diff --git a/src/compiler/UnfoldShortCircuit.h b/src/compiler/UnfoldShortCircuit.h
new file mode 100644
index 00000000..cb176a5f
--- /dev/null
+++ b/src/compiler/UnfoldShortCircuit.h
@@ -0,0 +1,39 @@
+//
+// 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.
+//
+// UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements
+//
+
+#ifndef COMPILER_UNFOLDSHORTCIRCUIT_H_
+#define COMPILER_UNFOLDSHORTCIRCUIT_H_
+
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+class OutputHLSL;
+
+class UnfoldShortCircuit : public TIntermTraverser
+{
+ public:
+ UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL);
+
+ void traverse(TIntermNode *node);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitSelection(Visit visit, TIntermSelection *node);
+ bool visitLoop(Visit visit, TIntermLoop *node);
+
+ int getNextTemporaryIndex();
+
+ protected:
+ TParseContext &mContext;
+ OutputHLSL *const mOutputHLSL;
+
+ int mTemporaryIndex;
+};
+}
+
+#endif // COMPILER_UNFOLDSHORTCIRCUIT_H_
diff --git a/src/compiler/Uniform.cpp b/src/compiler/Uniform.cpp
new file mode 100644
index 00000000..dcf3af1b
--- /dev/null
+++ b/src/compiler/Uniform.cpp
@@ -0,0 +1,21 @@
+//
+// 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.
+//
+
+#include "compiler/Uniform.h"
+
+namespace sh
+{
+
+Uniform::Uniform(GLenum type, GLenum precision, const char *name, int arraySize, int registerIndex)
+{
+ this->type = type;
+ this->precision = precision;
+ this->name = name;
+ this->arraySize = arraySize;
+ this->registerIndex = registerIndex;
+}
+
+}
diff --git a/src/compiler/Uniform.h b/src/compiler/Uniform.h
new file mode 100644
index 00000000..2ffd51ee
--- /dev/null
+++ b/src/compiler/Uniform.h
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_UNIFORM_H_
+#define COMPILER_UNIFORM_H_
+
+#include <string>
+#include <vector>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+namespace sh
+{
+
+struct Uniform
+{
+ Uniform(GLenum type, GLenum precision, const char *name, int arraySize, int registerIndex);
+
+ GLenum type;
+ GLenum precision;
+ std::string name;
+ unsigned int arraySize;
+
+ int registerIndex;
+};
+
+typedef std::vector<Uniform> ActiveUniforms;
+
+}
+
+#endif // COMPILER_UNIFORM_H_
diff --git a/src/compiler/ValidateLimitations.cpp b/src/compiler/ValidateLimitations.cpp
new file mode 100644
index 00000000..736ceeae
--- /dev/null
+++ b/src/compiler/ValidateLimitations.cpp
@@ -0,0 +1,512 @@
+//
+// 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.
+//
+
+#include "compiler/ValidateLimitations.h"
+#include "compiler/InfoSink.h"
+#include "compiler/InitializeParseContext.h"
+#include "compiler/ParseHelper.h"
+
+namespace {
+bool IsLoopIndex(const TIntermSymbol* symbol, const TLoopStack& stack) {
+ for (TLoopStack::const_iterator i = stack.begin(); i != stack.end(); ++i) {
+ if (i->index.id == symbol->getId())
+ return true;
+ }
+ return false;
+}
+
+void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) {
+ for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) {
+ if (i->index.id == symbol->getId()) {
+ ASSERT(i->loop != NULL);
+ i->loop->setUnrollFlag(true);
+ return;
+ }
+ }
+ UNREACHABLE();
+}
+
+// Traverses a node to check if it represents a constant index expression.
+// Definition:
+// constant-index-expressions are a superset of constant-expressions.
+// Constant-index-expressions can include loop indices as defined in
+// GLSL ES 1.0 spec, Appendix A, section 4.
+// The following are constant-index-expressions:
+// - Constant expressions
+// - Loop indices as defined in section 4
+// - Expressions composed of both of the above
+class ValidateConstIndexExpr : public TIntermTraverser {
+public:
+ ValidateConstIndexExpr(const TLoopStack& stack)
+ : mValid(true), mLoopStack(stack) {}
+
+ // Returns true if the parsed node represents a constant index expression.
+ bool isValid() const { return mValid; }
+
+ virtual void visitSymbol(TIntermSymbol* symbol) {
+ // Only constants and loop indices are allowed in a
+ // constant index expression.
+ if (mValid) {
+ mValid = (symbol->getQualifier() == EvqConst) ||
+ IsLoopIndex(symbol, mLoopStack);
+ }
+ }
+
+private:
+ bool mValid;
+ const TLoopStack& mLoopStack;
+};
+
+// Traverses a node to check if it uses a loop index.
+// If an int loop index is used in its body as a sampler array index,
+// mark the loop for unroll.
+class ValidateLoopIndexExpr : public TIntermTraverser {
+public:
+ ValidateLoopIndexExpr(TLoopStack& stack)
+ : mUsesFloatLoopIndex(false),
+ mUsesIntLoopIndex(false),
+ mLoopStack(stack) {}
+
+ bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; }
+ bool usesIntLoopIndex() const { return mUsesIntLoopIndex; }
+
+ virtual void visitSymbol(TIntermSymbol* symbol) {
+ if (IsLoopIndex(symbol, mLoopStack)) {
+ switch (symbol->getBasicType()) {
+ case EbtFloat:
+ mUsesFloatLoopIndex = true;
+ break;
+ case EbtInt:
+ mUsesIntLoopIndex = true;
+ MarkLoopForUnroll(symbol, mLoopStack);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ }
+
+private:
+ bool mUsesFloatLoopIndex;
+ bool mUsesIntLoopIndex;
+ TLoopStack& mLoopStack;
+};
+} // namespace
+
+ValidateLimitations::ValidateLimitations(ShShaderType shaderType,
+ TInfoSinkBase& sink)
+ : mShaderType(shaderType),
+ mSink(sink),
+ mNumErrors(0)
+{
+}
+
+bool ValidateLimitations::visitBinary(Visit, TIntermBinary* node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getLeft());
+
+ // Check indexing.
+ switch (node->getOp()) {
+ case EOpIndexDirect:
+ validateIndexing(node);
+ break;
+ case EOpIndexIndirect:
+#if defined(__APPLE__)
+ // Loop unrolling is a work-around for a Mac Cg compiler bug where it
+ // crashes when a sampler array's index is also the loop index.
+ // Once Apple fixes this bug, we should remove the code in this CL.
+ // See http://codereview.appspot.com/4331048/.
+ if ((node->getLeft() != NULL) && (node->getRight() != NULL) &&
+ (node->getLeft()->getAsSymbolNode())) {
+ TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode();
+ if (IsSampler(symbol->getBasicType()) && symbol->isArray()) {
+ ValidateLoopIndexExpr validate(mLoopStack);
+ node->getRight()->traverse(&validate);
+ if (validate.usesFloatLoopIndex()) {
+ error(node->getLine(),
+ "sampler array index is float loop index",
+ "for");
+ }
+ }
+ }
+#endif
+ validateIndexing(node);
+ break;
+ default: break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getOperand());
+
+ return true;
+}
+
+bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node)
+{
+ switch (node->getOp()) {
+ case EOpFunctionCall:
+ validateFunctionCall(node);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node)
+{
+ if (!validateLoopType(node))
+ return false;
+
+ TLoopInfo info;
+ memset(&info, 0, sizeof(TLoopInfo));
+ info.loop = node;
+ if (!validateForLoopHeader(node, &info))
+ return false;
+
+ TIntermNode* body = node->getBody();
+ if (body != NULL) {
+ mLoopStack.push_back(info);
+ body->traverse(this);
+ mLoopStack.pop_back();
+ }
+
+ // The loop is fully processed - no need to visit children.
+ return false;
+}
+
+void ValidateLimitations::error(TSourceLoc loc,
+ const char *reason, const char* token)
+{
+ mSink.prefix(EPrefixError);
+ mSink.location(loc);
+ mSink << "'" << token << "' : " << reason << "\n";
+ ++mNumErrors;
+}
+
+bool ValidateLimitations::withinLoopBody() const
+{
+ return !mLoopStack.empty();
+}
+
+bool ValidateLimitations::isLoopIndex(const TIntermSymbol* symbol) const
+{
+ return IsLoopIndex(symbol, mLoopStack);
+}
+
+bool ValidateLimitations::validateLoopType(TIntermLoop* node) {
+ TLoopType type = node->getType();
+ if (type == ELoopFor)
+ return true;
+
+ // Reject while and do-while loops.
+ error(node->getLine(),
+ "This type of loop is not allowed",
+ type == ELoopWhile ? "while" : "do");
+ return false;
+}
+
+bool ValidateLimitations::validateForLoopHeader(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ ASSERT(node->getType() == ELoopFor);
+
+ //
+ // The for statement has the form:
+ // for ( init-declaration ; condition ; expression ) statement
+ //
+ if (!validateForLoopInit(node, info))
+ return false;
+ if (!validateForLoopCond(node, info))
+ return false;
+ if (!validateForLoopExpr(node, info))
+ return false;
+
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopInit(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ TIntermNode* init = node->getInit();
+ if (init == NULL) {
+ error(node->getLine(), "Missing init declaration", "for");
+ return false;
+ }
+
+ //
+ // init-declaration has the form:
+ // type-specifier identifier = constant-expression
+ //
+ TIntermAggregate* decl = init->getAsAggregate();
+ if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) {
+ error(init->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ // To keep things simple do not allow declaration list.
+ TIntermSequence& declSeq = decl->getSequence();
+ if (declSeq.size() != 1) {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
+ if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
+ if (symbol == NULL) {
+ error(declInit->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ // The loop index has type int or float.
+ TBasicType type = symbol->getBasicType();
+ if ((type != EbtInt) && (type != EbtFloat)) {
+ error(symbol->getLine(),
+ "Invalid type for loop index", getBasicString(type));
+ return false;
+ }
+ // The loop index is initialized with constant expression.
+ if (!isConstExpr(declInit->getRight())) {
+ error(declInit->getLine(),
+ "Loop index cannot be initialized with non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+
+ info->index.id = symbol->getId();
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopCond(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ TIntermNode* cond = node->getCondition();
+ if (cond == NULL) {
+ error(node->getLine(), "Missing condition", "for");
+ return false;
+ }
+ //
+ // condition has the form:
+ // loop_index relational_operator constant_expression
+ //
+ TIntermBinary* binOp = cond->getAsBinaryNode();
+ if (binOp == NULL) {
+ error(node->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ // Loop index should be to the left of relational operator.
+ TIntermSymbol* symbol = binOp->getLeft()->getAsSymbolNode();
+ if (symbol == NULL) {
+ error(binOp->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ if (symbol->getId() != info->index.id) {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ return false;
+ }
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (binOp->getOp()) {
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ break;
+ default:
+ error(binOp->getLine(),
+ "Invalid relational operator",
+ getOperatorString(binOp->getOp()));
+ break;
+ }
+ // Loop index must be compared with a constant.
+ if (!isConstExpr(binOp->getRight())) {
+ error(binOp->getLine(),
+ "Loop index cannot be compared with non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ TIntermNode* expr = node->getExpression();
+ if (expr == NULL) {
+ error(node->getLine(), "Missing expression", "for");
+ return false;
+ }
+
+ // for expression has one of the following forms:
+ // loop_index++
+ // loop_index--
+ // loop_index += constant_expression
+ // loop_index -= constant_expression
+ // ++loop_index
+ // --loop_index
+ // The last two forms are not specified in the spec, but I am assuming
+ // its an oversight.
+ TIntermUnary* unOp = expr->getAsUnaryNode();
+ TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermSymbol* symbol = NULL;
+ if (unOp != NULL) {
+ op = unOp->getOp();
+ symbol = unOp->getOperand()->getAsSymbolNode();
+ } else if (binOp != NULL) {
+ op = binOp->getOp();
+ symbol = binOp->getLeft()->getAsSymbolNode();
+ }
+
+ // The operand must be loop index.
+ if (symbol == NULL) {
+ error(expr->getLine(), "Invalid expression", "for");
+ return false;
+ }
+ if (symbol->getId() != info->index.id) {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ return false;
+ }
+
+ // The operator is one of: ++ -- += -=.
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ break;
+ case EOpAddAssign:
+ case EOpSubAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ break;
+ default:
+ error(expr->getLine(), "Invalid operator", getOperatorString(op));
+ return false;
+ }
+
+ // Loop index must be incremented/decremented with a constant.
+ if (binOp != NULL) {
+ if (!isConstExpr(binOp->getRight())) {
+ error(binOp->getLine(),
+ "Loop index cannot be modified by non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node)
+{
+ ASSERT(node->getOp() == EOpFunctionCall);
+
+ // If not within loop body, there is nothing to check.
+ if (!withinLoopBody())
+ return true;
+
+ // List of param indices for which loop indices are used as argument.
+ typedef std::vector<size_t> ParamIndex;
+ ParamIndex pIndex;
+ TIntermSequence& params = node->getSequence();
+ for (TIntermSequence::size_type i = 0; i < params.size(); ++i) {
+ TIntermSymbol* symbol = params[i]->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol))
+ pIndex.push_back(i);
+ }
+ // If none of the loop indices are used as arguments,
+ // there is nothing to check.
+ if (pIndex.empty())
+ return true;
+
+ bool valid = true;
+ TSymbolTable& symbolTable = GetGlobalParseContext()->symbolTable;
+ TSymbol* symbol = symbolTable.find(node->getName());
+ ASSERT(symbol && symbol->isFunction());
+ TFunction* function = static_cast<TFunction*>(symbol);
+ for (ParamIndex::const_iterator i = pIndex.begin();
+ i != pIndex.end(); ++i) {
+ const TParameter& param = function->getParam(*i);
+ TQualifier qual = param.type->getQualifier();
+ if ((qual == EvqOut) || (qual == EvqInOut)) {
+ error(params[*i]->getLine(),
+ "Loop index cannot be used as argument to a function out or inout parameter",
+ params[*i]->getAsSymbolNode()->getSymbol().c_str());
+ valid = false;
+ }
+ }
+
+ return valid;
+}
+
+bool ValidateLimitations::validateOperation(TIntermOperator* node,
+ TIntermNode* operand) {
+ // Check if loop index is modified in the loop body.
+ if (!withinLoopBody() || !node->modifiesState())
+ return true;
+
+ const TIntermSymbol* symbol = operand->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol)) {
+ error(node->getLine(),
+ "Loop index cannot be statically assigned to within the body of the loop",
+ symbol->getSymbol().c_str());
+ }
+ return true;
+}
+
+bool ValidateLimitations::isConstExpr(TIntermNode* node)
+{
+ ASSERT(node != NULL);
+ return node->getAsConstantUnion() != NULL;
+}
+
+bool ValidateLimitations::isConstIndexExpr(TIntermNode* node)
+{
+ ASSERT(node != NULL);
+
+ ValidateConstIndexExpr validate(mLoopStack);
+ node->traverse(&validate);
+ return validate.isValid();
+}
+
+bool ValidateLimitations::validateIndexing(TIntermBinary* node)
+{
+ ASSERT((node->getOp() == EOpIndexDirect) ||
+ (node->getOp() == EOpIndexIndirect));
+
+ bool valid = true;
+ TIntermTyped* index = node->getRight();
+ // The index expression must have integral type.
+ if (!index->isScalar() || (index->getBasicType() != EbtInt)) {
+ error(index->getLine(),
+ "Index expression must have integral type",
+ index->getCompleteString().c_str());
+ valid = false;
+ }
+ // The index expession must be a constant-index-expression unless
+ // the operand is a uniform in a vertex shader.
+ TIntermTyped* operand = node->getLeft();
+ bool skip = (mShaderType == SH_VERTEX_SHADER) &&
+ (operand->getQualifier() == EvqUniform);
+ if (!skip && !isConstIndexExpr(index)) {
+ error(index->getLine(), "Index expression must be constant", "[]");
+ valid = false;
+ }
+ return valid;
+}
+
diff --git a/src/compiler/ValidateLimitations.h b/src/compiler/ValidateLimitations.h
new file mode 100644
index 00000000..a835cb3c
--- /dev/null
+++ b/src/compiler/ValidateLimitations.h
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 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.
+//
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+
+class TInfoSinkBase;
+
+struct TLoopInfo {
+ struct TIndex {
+ int id; // symbol id.
+ } index;
+ TIntermLoop* loop;
+};
+typedef TVector<TLoopInfo> TLoopStack;
+
+// Traverses intermediate tree to ensure that the shader does not exceed the
+// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
+class ValidateLimitations : public TIntermTraverser {
+public:
+ ValidateLimitations(ShShaderType shaderType, TInfoSinkBase& sink);
+
+ int numErrors() const { return mNumErrors; }
+
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+
+private:
+ void error(TSourceLoc loc, const char *reason, const char* token);
+
+ bool withinLoopBody() const;
+ bool isLoopIndex(const TIntermSymbol* symbol) const;
+ bool validateLoopType(TIntermLoop* node);
+ bool validateForLoopHeader(TIntermLoop* node, TLoopInfo* info);
+ bool validateForLoopInit(TIntermLoop* node, TLoopInfo* info);
+ bool validateForLoopCond(TIntermLoop* node, TLoopInfo* info);
+ bool validateForLoopExpr(TIntermLoop* node, TLoopInfo* info);
+ // Returns true if none of the loop indices is used as the argument to
+ // the given function out or inout parameter.
+ bool validateFunctionCall(TIntermAggregate* node);
+ bool validateOperation(TIntermOperator* node, TIntermNode* operand);
+
+ // Returns true if indexing does not exceed the minimum functionality
+ // mandated in GLSL 1.0 spec, Appendix A, Section 5.
+ bool isConstExpr(TIntermNode* node);
+ bool isConstIndexExpr(TIntermNode* node);
+ bool validateIndexing(TIntermBinary* node);
+
+ ShShaderType mShaderType;
+ TInfoSinkBase& mSink;
+ int mNumErrors;
+ TLoopStack mLoopStack;
+};
+
diff --git a/src/compiler/VariableInfo.cpp b/src/compiler/VariableInfo.cpp
new file mode 100644
index 00000000..84db807a
--- /dev/null
+++ b/src/compiler/VariableInfo.cpp
@@ -0,0 +1,245 @@
+//
+// 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.
+//
+
+#include "compiler/VariableInfo.h"
+
+static TString arrayBrackets(int index)
+{
+ TStringStream stream;
+ stream << "[" << index << "]";
+ return stream.str();
+}
+
+// Returns the data type for an attribute or uniform.
+static ShDataType getVariableDataType(const TType& type)
+{
+ switch (type.getBasicType()) {
+ case EbtFloat:
+ if (type.isMatrix()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_FLOAT_MAT2;
+ case 3: return SH_FLOAT_MAT3;
+ case 4: return SH_FLOAT_MAT4;
+ default: UNREACHABLE();
+ }
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_FLOAT_VEC2;
+ case 3: return SH_FLOAT_VEC3;
+ case 4: return SH_FLOAT_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_FLOAT;
+ }
+ case EbtInt:
+ if (type.isMatrix()) {
+ UNREACHABLE();
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_INT_VEC2;
+ case 3: return SH_INT_VEC3;
+ case 4: return SH_INT_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_INT;
+ }
+ case EbtBool:
+ if (type.isMatrix()) {
+ UNREACHABLE();
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_BOOL_VEC2;
+ case 3: return SH_BOOL_VEC3;
+ case 4: return SH_BOOL_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_BOOL;
+ }
+ case EbtSampler2D: return SH_SAMPLER_2D;
+ case EbtSamplerCube: return SH_SAMPLER_CUBE;
+ case EbtSamplerExternalOES: return SH_SAMPLER_EXTERNAL_OES;
+ case EbtSampler2DRect: return SH_SAMPLER_2D_RECT_ARB;
+ default: UNREACHABLE();
+ }
+ return SH_NONE;
+}
+
+static void getBuiltInVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList);
+static void getUserDefinedVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList,
+ ShHashFunction64 hashFunction);
+
+// Returns info for an attribute or uniform.
+static void getVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList,
+ ShHashFunction64 hashFunction)
+{
+ if (type.getBasicType() == EbtStruct) {
+ if (type.isArray()) {
+ for (int i = 0; i < type.getArraySize(); ++i) {
+ TString lname = name + arrayBrackets(i);
+ TString lmappedName = mappedName + arrayBrackets(i);
+ getUserDefinedVariableInfo(type, lname, lmappedName, infoList, hashFunction);
+ }
+ } else {
+ getUserDefinedVariableInfo(type, name, mappedName, infoList, hashFunction);
+ }
+ } else {
+ getBuiltInVariableInfo(type, name, mappedName, infoList);
+ }
+}
+
+void getBuiltInVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList)
+{
+ ASSERT(type.getBasicType() != EbtStruct);
+
+ TVariableInfo varInfo;
+ if (type.isArray()) {
+ varInfo.name = (name + "[0]").c_str();
+ varInfo.mappedName = (mappedName + "[0]").c_str();
+ varInfo.size = type.getArraySize();
+ } else {
+ varInfo.name = name.c_str();
+ varInfo.mappedName = mappedName.c_str();
+ varInfo.size = 1;
+ }
+ varInfo.type = getVariableDataType(type);
+ infoList.push_back(varInfo);
+}
+
+void getUserDefinedVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList,
+ ShHashFunction64 hashFunction)
+{
+ ASSERT(type.getBasicType() == EbtStruct);
+
+ const TFieldList& fields = type.getStruct()->fields();
+ for (size_t i = 0; i < fields.size(); ++i) {
+ const TType& fieldType = *(fields[i]->type());
+ const TString& fieldName = fields[i]->name();
+ getVariableInfo(fieldType,
+ name + "." + fieldName,
+ mappedName + "." + TIntermTraverser::hash(fieldName, hashFunction),
+ infoList,
+ hashFunction);
+ }
+}
+
+TVariableInfo::TVariableInfo()
+{
+}
+
+TVariableInfo::TVariableInfo(ShDataType type, int size)
+ : type(type),
+ size(size)
+{
+}
+
+CollectAttribsUniforms::CollectAttribsUniforms(TVariableInfoList& attribs,
+ TVariableInfoList& uniforms,
+ ShHashFunction64 hashFunction)
+ : mAttribs(attribs),
+ mUniforms(uniforms),
+ mHashFunction(hashFunction)
+{
+}
+
+// We are only interested in attribute and uniform variable declaration.
+void CollectAttribsUniforms::visitSymbol(TIntermSymbol*)
+{
+}
+
+void CollectAttribsUniforms::visitConstantUnion(TIntermConstantUnion*)
+{
+}
+
+bool CollectAttribsUniforms::visitBinary(Visit, TIntermBinary*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitUnary(Visit, TIntermUnary*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitSelection(Visit, TIntermSelection*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitAggregate(Visit, TIntermAggregate* node)
+{
+ bool visitChildren = false;
+
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ // We need to visit sequence children to get to variable declarations.
+ visitChildren = true;
+ break;
+ case EOpDeclaration: {
+ const TIntermSequence& sequence = node->getSequence();
+ TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
+ if (qualifier == EvqAttribute || qualifier == EvqUniform)
+ {
+ TVariableInfoList& infoList = qualifier == EvqAttribute ?
+ mAttribs : mUniforms;
+ for (TIntermSequence::const_iterator i = sequence.begin();
+ i != sequence.end(); ++i)
+ {
+ const TIntermSymbol* variable = (*i)->getAsSymbolNode();
+ // The only case in which the sequence will not contain a
+ // TIntermSymbol node is initialization. It will contain a
+ // TInterBinary node in that case. Since attributes and unifroms
+ // cannot be initialized in a shader, we must have only
+ // TIntermSymbol nodes in the sequence.
+ ASSERT(variable != NULL);
+ TString processedSymbol;
+ if (mHashFunction == NULL)
+ processedSymbol = variable->getSymbol();
+ else
+ processedSymbol = TIntermTraverser::hash(variable->getOriginalSymbol(), mHashFunction);
+ getVariableInfo(variable->getType(),
+ variable->getOriginalSymbol(),
+ processedSymbol,
+ infoList,
+ mHashFunction);
+ }
+ }
+ break;
+ }
+ default: break;
+ }
+
+ return visitChildren;
+}
+
+bool CollectAttribsUniforms::visitLoop(Visit, TIntermLoop*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitBranch(Visit, TIntermBranch*)
+{
+ return false;
+}
+
diff --git a/src/compiler/VariableInfo.h b/src/compiler/VariableInfo.h
new file mode 100644
index 00000000..4130a589
--- /dev/null
+++ b/src/compiler/VariableInfo.h
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_VARIABLE_INFO_H_
+#define COMPILER_VARIABLE_INFO_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+
+// Provides information about a variable.
+// It is currently being used to store info about active attribs and uniforms.
+struct TVariableInfo {
+ TVariableInfo(ShDataType type, int size);
+ TVariableInfo();
+
+ TPersistString name;
+ TPersistString mappedName;
+ ShDataType type;
+ int size;
+};
+typedef std::vector<TVariableInfo> TVariableInfoList;
+
+// Traverses intermediate tree to collect all attributes and uniforms.
+class CollectAttribsUniforms : public TIntermTraverser {
+public:
+ CollectAttribsUniforms(TVariableInfoList& attribs,
+ TVariableInfoList& uniforms,
+ ShHashFunction64 hashFunction);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual void visitConstantUnion(TIntermConstantUnion*);
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitSelection(Visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+ virtual bool visitBranch(Visit, TIntermBranch*);
+
+private:
+ TVariableInfoList& mAttribs;
+ TVariableInfoList& mUniforms;
+
+ ShHashFunction64 mHashFunction;
+};
+
+#endif // COMPILER_VARIABLE_INFO_H_
diff --git a/src/compiler/VariablePacker.cpp b/src/compiler/VariablePacker.cpp
new file mode 100644
index 00000000..89572877
--- /dev/null
+++ b/src/compiler/VariablePacker.cpp
@@ -0,0 +1,297 @@
+//
+// 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.
+//
+#include "compiler/VariablePacker.h"
+
+#include <algorithm>
+#include "compiler/ShHandle.h"
+
+namespace {
+int GetSortOrder(ShDataType type)
+{
+ switch (type) {
+ case SH_FLOAT_MAT4:
+ return 0;
+ case SH_FLOAT_MAT2:
+ return 1;
+ case SH_FLOAT_VEC4:
+ case SH_INT_VEC4:
+ case SH_BOOL_VEC4:
+ return 2;
+ case SH_FLOAT_MAT3:
+ return 3;
+ case SH_FLOAT_VEC3:
+ case SH_INT_VEC3:
+ case SH_BOOL_VEC3:
+ return 4;
+ case SH_FLOAT_VEC2:
+ case SH_INT_VEC2:
+ case SH_BOOL_VEC2:
+ return 5;
+ case SH_FLOAT:
+ case SH_INT:
+ case SH_BOOL:
+ case SH_SAMPLER_2D:
+ case SH_SAMPLER_CUBE:
+ case SH_SAMPLER_EXTERNAL_OES:
+ case SH_SAMPLER_2D_RECT_ARB:
+ return 6;
+ default:
+ ASSERT(false);
+ return 7;
+ }
+}
+} // namespace
+
+int VariablePacker::GetNumComponentsPerRow(ShDataType type)
+{
+ switch (type) {
+ case SH_FLOAT_MAT4:
+ case SH_FLOAT_MAT2:
+ case SH_FLOAT_VEC4:
+ case SH_INT_VEC4:
+ case SH_BOOL_VEC4:
+ return 4;
+ case SH_FLOAT_MAT3:
+ case SH_FLOAT_VEC3:
+ case SH_INT_VEC3:
+ case SH_BOOL_VEC3:
+ return 3;
+ case SH_FLOAT_VEC2:
+ case SH_INT_VEC2:
+ case SH_BOOL_VEC2:
+ return 2;
+ case SH_FLOAT:
+ case SH_INT:
+ case SH_BOOL:
+ case SH_SAMPLER_2D:
+ case SH_SAMPLER_CUBE:
+ case SH_SAMPLER_EXTERNAL_OES:
+ case SH_SAMPLER_2D_RECT_ARB:
+ return 1;
+ default:
+ ASSERT(false);
+ return 5;
+ }
+}
+
+int VariablePacker::GetNumRows(ShDataType type)
+{
+ switch (type) {
+ case SH_FLOAT_MAT4:
+ return 4;
+ case SH_FLOAT_MAT3:
+ return 3;
+ case SH_FLOAT_MAT2:
+ return 2;
+ case SH_FLOAT_VEC4:
+ case SH_INT_VEC4:
+ case SH_BOOL_VEC4:
+ case SH_FLOAT_VEC3:
+ case SH_INT_VEC3:
+ case SH_BOOL_VEC3:
+ case SH_FLOAT_VEC2:
+ case SH_INT_VEC2:
+ case SH_BOOL_VEC2:
+ case SH_FLOAT:
+ case SH_INT:
+ case SH_BOOL:
+ case SH_SAMPLER_2D:
+ case SH_SAMPLER_CUBE:
+ case SH_SAMPLER_EXTERNAL_OES:
+ case SH_SAMPLER_2D_RECT_ARB:
+ return 1;
+ default:
+ ASSERT(false);
+ return 100000;
+ }
+}
+
+struct TVariableInfoComparer {
+ bool operator()(const TVariableInfo& lhs, const TVariableInfo& rhs) const
+ {
+ int lhsSortOrder = GetSortOrder(lhs.type);
+ int rhsSortOrder = GetSortOrder(rhs.type);
+ if (lhsSortOrder != rhsSortOrder) {
+ return lhsSortOrder < rhsSortOrder;
+ }
+ // Sort by largest first.
+ return lhs.size > rhs.size;
+ }
+};
+
+unsigned VariablePacker::makeColumnFlags(int column, int numComponentsPerRow)
+{
+ return ((kColumnMask << (kNumColumns - numComponentsPerRow)) &
+ kColumnMask) >> column;
+}
+
+void VariablePacker::fillColumns(int topRow, int numRows, int column, int numComponentsPerRow)
+{
+ unsigned columnFlags = makeColumnFlags(column, numComponentsPerRow);
+ for (int r = 0; r < numRows; ++r) {
+ int row = topRow + r;
+ ASSERT((rows_[row] & columnFlags) == 0);
+ rows_[row] |= columnFlags;
+ }
+}
+
+bool VariablePacker::searchColumn(int column, int numRows, int* destRow, int* destSize)
+{
+ ASSERT(destRow);
+
+ for (; topNonFullRow_ < maxRows_ && rows_[topNonFullRow_] == kColumnMask;
+ ++topNonFullRow_) {
+ }
+
+ for (; bottomNonFullRow_ >= 0 && rows_[bottomNonFullRow_] == kColumnMask;
+ --bottomNonFullRow_) {
+ }
+
+ if (bottomNonFullRow_ - topNonFullRow_ + 1 < numRows) {
+ return false;
+ }
+
+ unsigned columnFlags = makeColumnFlags(column, 1);
+ int topGoodRow = 0;
+ int smallestGoodTop = -1;
+ int smallestGoodSize = maxRows_ + 1;
+ int bottomRow = bottomNonFullRow_ + 1;
+ bool found = false;
+ for (int row = topNonFullRow_; row <= bottomRow; ++row) {
+ bool rowEmpty = row < bottomRow ? ((rows_[row] & columnFlags) == 0) : false;
+ if (rowEmpty) {
+ if (!found) {
+ topGoodRow = row;
+ found = true;
+ }
+ } else {
+ if (found) {
+ int size = row - topGoodRow;
+ if (size >= numRows && size < smallestGoodSize) {
+ smallestGoodSize = size;
+ smallestGoodTop = topGoodRow;
+ }
+ }
+ found = false;
+ }
+ }
+ if (smallestGoodTop < 0) {
+ return false;
+ }
+
+ *destRow = smallestGoodTop;
+ if (destSize) {
+ *destSize = smallestGoodSize;
+ }
+ return true;
+}
+
+bool VariablePacker::CheckVariablesWithinPackingLimits(int maxVectors, const TVariableInfoList& in_variables)
+{
+ ASSERT(maxVectors > 0);
+ maxRows_ = maxVectors;
+ topNonFullRow_ = 0;
+ bottomNonFullRow_ = maxRows_ - 1;
+ TVariableInfoList variables(in_variables);
+
+ // As per GLSL 1.017 Appendix A, Section 7 variables are packed in specific
+ // order by type, then by size of array, largest first.
+ std::sort(variables.begin(), variables.end(), TVariableInfoComparer());
+ rows_.clear();
+ rows_.resize(maxVectors, 0);
+
+ // Packs the 4 column variables.
+ size_t ii = 0;
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ if (GetNumComponentsPerRow(variable.type) != 4) {
+ break;
+ }
+ topNonFullRow_ += GetNumRows(variable.type) * variable.size;
+ }
+
+ if (topNonFullRow_ > maxRows_) {
+ return false;
+ }
+
+ // Packs the 3 column variables.
+ int num3ColumnRows = 0;
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ if (GetNumComponentsPerRow(variable.type) != 3) {
+ break;
+ }
+ num3ColumnRows += GetNumRows(variable.type) * variable.size;
+ }
+
+ if (topNonFullRow_ + num3ColumnRows > maxRows_) {
+ return false;
+ }
+
+ fillColumns(topNonFullRow_, num3ColumnRows, 0, 3);
+
+ // Packs the 2 column variables.
+ int top2ColumnRow = topNonFullRow_ + num3ColumnRows;
+ int twoColumnRowsAvailable = maxRows_ - top2ColumnRow;
+ int rowsAvailableInColumns01 = twoColumnRowsAvailable;
+ int rowsAvailableInColumns23 = twoColumnRowsAvailable;
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ if (GetNumComponentsPerRow(variable.type) != 2) {
+ break;
+ }
+ int numRows = GetNumRows(variable.type) * variable.size;
+ if (numRows <= rowsAvailableInColumns01) {
+ rowsAvailableInColumns01 -= numRows;
+ } else if (numRows <= rowsAvailableInColumns23) {
+ rowsAvailableInColumns23 -= numRows;
+ } else {
+ return false;
+ }
+ }
+
+ int numRowsUsedInColumns01 =
+ twoColumnRowsAvailable - rowsAvailableInColumns01;
+ int numRowsUsedInColumns23 =
+ twoColumnRowsAvailable - rowsAvailableInColumns23;
+ fillColumns(top2ColumnRow, numRowsUsedInColumns01, 0, 2);
+ fillColumns(maxRows_ - numRowsUsedInColumns23, numRowsUsedInColumns23,
+ 2, 2);
+
+ // Packs the 1 column variables.
+ for (; ii < variables.size(); ++ii) {
+ const TVariableInfo& variable = variables[ii];
+ ASSERT(1 == GetNumComponentsPerRow(variable.type));
+ int numRows = GetNumRows(variable.type) * variable.size;
+ int smallestColumn = -1;
+ int smallestSize = maxRows_ + 1;
+ int topRow = -1;
+ for (int column = 0; column < kNumColumns; ++column) {
+ int row = 0;
+ int size = 0;
+ if (searchColumn(column, numRows, &row, &size)) {
+ if (size < smallestSize) {
+ smallestSize = size;
+ smallestColumn = column;
+ topRow = row;
+ }
+ }
+ }
+
+ if (smallestColumn < 0) {
+ return false;
+ }
+
+ fillColumns(topRow, numRows, smallestColumn, 1);
+ }
+
+ ASSERT(variables.size() == ii);
+
+ return true;
+}
+
+
+
diff --git a/src/compiler/VariablePacker.h b/src/compiler/VariablePacker.h
new file mode 100644
index 00000000..8987066c
--- /dev/null
+++ b/src/compiler/VariablePacker.h
@@ -0,0 +1,41 @@
+//
+// 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.
+//
+
+#ifndef _VARIABLEPACKER_INCLUDED_
+#define _VARIABLEPACKER_INCLUDED_
+
+#include <vector>
+#include "compiler/ShHandle.h"
+
+class VariablePacker {
+ public:
+ // Returns true if the passed in variables pack in maxVectors following
+ // the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
+ bool CheckVariablesWithinPackingLimits(
+ int maxVectors,
+ const TVariableInfoList& in_variables);
+
+ // Gets how many components in a row a data type takes.
+ static int GetNumComponentsPerRow(ShDataType type);
+
+ // Gets how many rows a data type takes.
+ static int GetNumRows(ShDataType type);
+
+ private:
+ static const int kNumColumns = 4;
+ static const unsigned kColumnMask = (1 << kNumColumns) - 1;
+
+ unsigned makeColumnFlags(int column, int numComponentsPerRow);
+ void fillColumns(int topRow, int numRows, int column, int numComponentsPerRow);
+ bool searchColumn(int column, int numRows, int* destRow, int* destSize);
+
+ int topNonFullRow_;
+ int bottomNonFullRow_;
+ int maxRows_;
+ std::vector<unsigned> rows_;
+};
+
+#endif // _VARIABLEPACKER_INCLUDED_
diff --git a/src/compiler/VersionGLSL.cpp b/src/compiler/VersionGLSL.cpp
new file mode 100644
index 00000000..7a82bb4d
--- /dev/null
+++ b/src/compiler/VersionGLSL.cpp
@@ -0,0 +1,140 @@
+//
+// 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.
+//
+
+#include "compiler/VersionGLSL.h"
+
+static const int GLSL_VERSION_110 = 110;
+static const int GLSL_VERSION_120 = 120;
+
+// We need to scan for the following:
+// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders
+// but only at the global scope.
+// 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader
+// but inside any scope.
+// 3. Call to a matrix constructor with another matrix as argument.
+// (These constructors were reserved in GLSL version 1.10.)
+// 4. Arrays as "out" function parameters.
+// GLSL spec section 6.1.1: "When calling a function, expressions that do
+// not evaluate to l-values cannot be passed to parameters declared as
+// out or inout."
+// GLSL 1.1 section 5.8: "Other binary or unary expressions,
+// non-dereferenced arrays, function names, swizzles with repeated fields,
+// and constants cannot be l-values."
+// GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that
+// are built-in types, entire structures or arrays... are all l-values."
+//
+// TODO(alokp): The following two cases of invariant decalaration get lost
+// during parsing - they do not get carried over to the intermediate tree.
+// Handle these cases:
+// 1. When a pragma is used to force all output variables to be invariant:
+// - #pragma STDGL invariant(all)
+// 2. When a previously decalared or built-in variable is marked invariant:
+// - invariant gl_Position;
+// - varying vec3 color; invariant color;
+//
+TVersionGLSL::TVersionGLSL(ShShaderType type)
+ : mShaderType(type),
+ mVersion(GLSL_VERSION_110)
+{
+}
+
+void TVersionGLSL::visitSymbol(TIntermSymbol* node)
+{
+ if (node->getSymbol() == "gl_PointCoord")
+ updateVersion(GLSL_VERSION_120);
+}
+
+void TVersionGLSL::visitConstantUnion(TIntermConstantUnion*)
+{
+}
+
+bool TVersionGLSL::visitBinary(Visit, TIntermBinary*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitUnary(Visit, TIntermUnary*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitSelection(Visit, TIntermSelection*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate* node)
+{
+ bool visitChildren = true;
+
+ switch (node->getOp()) {
+ case EOpSequence:
+ // We need to visit sequence children to get to global or inner scope.
+ visitChildren = true;
+ break;
+ case EOpDeclaration: {
+ const TIntermSequence& sequence = node->getSequence();
+ TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
+ if ((qualifier == EvqInvariantVaryingIn) ||
+ (qualifier == EvqInvariantVaryingOut)) {
+ updateVersion(GLSL_VERSION_120);
+ }
+ break;
+ }
+ case EOpParameters: {
+ const TIntermSequence& params = node->getSequence();
+ for (TIntermSequence::const_iterator iter = params.begin();
+ iter != params.end(); ++iter)
+ {
+ const TIntermTyped* param = (*iter)->getAsTyped();
+ if (param->isArray())
+ {
+ TQualifier qualifier = param->getQualifier();
+ if ((qualifier == EvqOut) || (qualifier == EvqInOut))
+ {
+ updateVersion(GLSL_VERSION_120);
+ break;
+ }
+ }
+ }
+ // Fully processed. No need to visit children.
+ visitChildren = false;
+ break;
+ }
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4: {
+ const TIntermSequence& sequence = node->getSequence();
+ if (sequence.size() == 1) {
+ TIntermTyped* typed = sequence.front()->getAsTyped();
+ if (typed && typed->isMatrix()) {
+ updateVersion(GLSL_VERSION_120);
+ }
+ }
+ break;
+ }
+
+ default: break;
+ }
+
+ return visitChildren;
+}
+
+bool TVersionGLSL::visitLoop(Visit, TIntermLoop*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitBranch(Visit, TIntermBranch*)
+{
+ return true;
+}
+
+void TVersionGLSL::updateVersion(int version)
+{
+ mVersion = std::max(version, mVersion);
+}
+
diff --git a/src/compiler/VersionGLSL.h b/src/compiler/VersionGLSL.h
new file mode 100644
index 00000000..1c1cb1ab
--- /dev/null
+++ b/src/compiler/VersionGLSL.h
@@ -0,0 +1,56 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_VERSIONGLSL_H_
+#define COMPILER_VERSIONGLSL_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+
+// Traverses the intermediate tree to return the minimum GLSL version
+// required to legally access all built-in features used in the shader.
+// GLSL 1.1 which is mandated by OpenGL 2.0 provides:
+// - #version and #extension to declare version and extensions.
+// - built-in functions refract, exp, and log.
+// - updated step() to compare x < edge instead of x <= edge.
+// GLSL 1.2 which is mandated by OpenGL 2.1 provides:
+// - many changes to reduce differences when compared to the ES specification.
+// - invariant keyword and its support.
+// - c++ style name hiding rules.
+// - built-in variable gl_PointCoord for fragment shaders.
+// - matrix constructors taking matrix as argument.
+// - array as "out" function parameters
+//
+class TVersionGLSL : public TIntermTraverser {
+public:
+ TVersionGLSL(ShShaderType type);
+
+ // Returns 120 if the following is used the shader:
+ // - "invariant",
+ // - "gl_PointCoord",
+ // - matrix/matrix constructors
+ // - array "out" parameters
+ // Else 110 is returned.
+ int getVersion() { return mVersion; }
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual void visitConstantUnion(TIntermConstantUnion*);
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitSelection(Visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+ virtual bool visitBranch(Visit, TIntermBranch*);
+
+protected:
+ void updateVersion(int version);
+
+private:
+ ShShaderType mShaderType;
+ int mVersion;
+};
+
+#endif // COMPILER_VERSIONGLSL_H_
diff --git a/src/compiler/debug.cpp b/src/compiler/debug.cpp
new file mode 100644
index 00000000..53778bd3
--- /dev/null
+++ b/src/compiler/debug.cpp
@@ -0,0 +1,37 @@
+//
+// 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.
+//
+
+// debug.cpp: Debugging utilities.
+
+#include "compiler/debug.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "compiler/InitializeParseContext.h"
+#include "compiler/ParseHelper.h"
+
+static const int kTraceBufferLen = 1024;
+
+#ifdef TRACE_ENABLED
+extern "C" {
+void Trace(const char *format, ...) {
+ if (!format) return;
+
+ TParseContext* parseContext = GetGlobalParseContext();
+ if (parseContext) {
+ char buf[kTraceBufferLen];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buf, kTraceBufferLen, format, args);
+ va_end(args);
+
+ parseContext->trace(buf);
+ }
+}
+} // extern "C"
+#endif // TRACE_ENABLED
+
diff --git a/src/compiler/debug.h b/src/compiler/debug.h
new file mode 100644
index 00000000..7a371516
--- /dev/null
+++ b/src/compiler/debug.h
@@ -0,0 +1,53 @@
+//
+// 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.
+//
+
+// debug.h: Debugging utilities.
+
+#ifndef COMPILER_DEBUG_H_
+#define COMPILER_DEBUG_H_
+
+#include <assert.h>
+
+#ifdef _DEBUG
+#define TRACE_ENABLED // define to enable debug message tracing
+#endif // _DEBUG
+
+// Outputs text to the debug log
+#ifdef TRACE_ENABLED
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+void Trace(const char* format, ...);
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#else // TRACE_ENABLED
+
+#define Trace(...) ((void)0)
+
+#endif // TRACE_ENABLED
+
+// A macro asserting a condition and outputting failures to the debug log
+#define ASSERT(expression) do { \
+ if(!(expression)) \
+ Trace("Assert failed: %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \
+ assert(expression); \
+} while(0)
+
+#define UNIMPLEMENTED() do { \
+ Trace("Unimplemented invoked: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+} while(0)
+
+#define UNREACHABLE() do { \
+ Trace("Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+} while(0)
+
+#endif // COMPILER_DEBUG_H_
+
diff --git a/src/compiler/depgraph/DependencyGraph.cpp b/src/compiler/depgraph/DependencyGraph.cpp
new file mode 100644
index 00000000..ca661d67
--- /dev/null
+++ b/src/compiler/depgraph/DependencyGraph.cpp
@@ -0,0 +1,97 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#pragma warning(disable: 4718)
+
+#include "compiler/depgraph/DependencyGraph.h"
+#include "compiler/depgraph/DependencyGraphBuilder.h"
+
+TDependencyGraph::TDependencyGraph(TIntermNode* intermNode)
+{
+ TDependencyGraphBuilder::build(intermNode, this);
+}
+
+TDependencyGraph::~TDependencyGraph()
+{
+ for (TGraphNodeVector::const_iterator iter = mAllNodes.begin(); iter != mAllNodes.end(); ++iter)
+ {
+ TGraphNode* node = *iter;
+ delete node;
+ }
+}
+
+TGraphArgument* TDependencyGraph::createArgument(TIntermAggregate* intermFunctionCall,
+ int argumentNumber)
+{
+ TGraphArgument* argument = new TGraphArgument(intermFunctionCall, argumentNumber);
+ mAllNodes.push_back(argument);
+ return argument;
+}
+
+TGraphFunctionCall* TDependencyGraph::createFunctionCall(TIntermAggregate* intermFunctionCall)
+{
+ TGraphFunctionCall* functionCall = new TGraphFunctionCall(intermFunctionCall);
+ mAllNodes.push_back(functionCall);
+ if (functionCall->getIntermFunctionCall()->isUserDefined())
+ mUserDefinedFunctionCalls.push_back(functionCall);
+ return functionCall;
+}
+
+TGraphSymbol* TDependencyGraph::getOrCreateSymbol(TIntermSymbol* intermSymbol)
+{
+ TSymbolIdMap::const_iterator iter = mSymbolIdMap.find(intermSymbol->getId());
+
+ TGraphSymbol* symbol = NULL;
+
+ if (iter != mSymbolIdMap.end()) {
+ TSymbolIdPair pair = *iter;
+ symbol = pair.second;
+ } else {
+ symbol = new TGraphSymbol(intermSymbol);
+ mAllNodes.push_back(symbol);
+
+ TSymbolIdPair pair(intermSymbol->getId(), symbol);
+ mSymbolIdMap.insert(pair);
+
+ // We save all sampler symbols in a collection, so we can start graph traversals from them quickly.
+ if (IsSampler(intermSymbol->getBasicType()))
+ mSamplerSymbols.push_back(symbol);
+ }
+
+ return symbol;
+}
+
+TGraphSelection* TDependencyGraph::createSelection(TIntermSelection* intermSelection)
+{
+ TGraphSelection* selection = new TGraphSelection(intermSelection);
+ mAllNodes.push_back(selection);
+ return selection;
+}
+
+TGraphLoop* TDependencyGraph::createLoop(TIntermLoop* intermLoop)
+{
+ TGraphLoop* loop = new TGraphLoop(intermLoop);
+ mAllNodes.push_back(loop);
+ return loop;
+}
+
+TGraphLogicalOp* TDependencyGraph::createLogicalOp(TIntermBinary* intermLogicalOp)
+{
+ TGraphLogicalOp* logicalOp = new TGraphLogicalOp(intermLogicalOp);
+ mAllNodes.push_back(logicalOp);
+ return logicalOp;
+}
+
+const char* TGraphLogicalOp::getOpString() const
+{
+ const char* opString = NULL;
+ switch (getIntermLogicalOp()->getOp()) {
+ case EOpLogicalAnd: opString = "and"; break;
+ case EOpLogicalOr: opString = "or"; break;
+ default: opString = "unknown"; break;
+ }
+ return opString;
+}
diff --git a/src/compiler/depgraph/DependencyGraph.h b/src/compiler/depgraph/DependencyGraph.h
new file mode 100644
index 00000000..5a9c35d0
--- /dev/null
+++ b/src/compiler/depgraph/DependencyGraph.h
@@ -0,0 +1,212 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H
+#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H
+
+#include "compiler/intermediate.h"
+
+#include <set>
+#include <stack>
+
+class TGraphNode;
+class TGraphParentNode;
+class TGraphArgument;
+class TGraphFunctionCall;
+class TGraphSymbol;
+class TGraphSelection;
+class TGraphLoop;
+class TGraphLogicalOp;
+class TDependencyGraphTraverser;
+class TDependencyGraphOutput;
+
+typedef std::set<TGraphNode*> TGraphNodeSet;
+typedef std::vector<TGraphNode*> TGraphNodeVector;
+typedef std::vector<TGraphSymbol*> TGraphSymbolVector;
+typedef std::vector<TGraphFunctionCall*> TFunctionCallVector;
+
+//
+// Base class for all dependency graph nodes.
+//
+class TGraphNode {
+public:
+ TGraphNode(TIntermNode* node) : intermNode(node) {}
+ virtual ~TGraphNode() {}
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+protected:
+ TIntermNode* intermNode;
+};
+
+//
+// Base class for dependency graph nodes that may have children.
+//
+class TGraphParentNode : public TGraphNode {
+public:
+ TGraphParentNode(TIntermNode* node) : TGraphNode(node) {}
+ virtual ~TGraphParentNode() {}
+ void addDependentNode(TGraphNode* node) { if (node != this) mDependentNodes.insert(node); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+private:
+ TGraphNodeSet mDependentNodes;
+};
+
+//
+// Handle function call arguments.
+//
+class TGraphArgument : public TGraphParentNode {
+public:
+ TGraphArgument(TIntermAggregate* intermFunctionCall, int argumentNumber)
+ : TGraphParentNode(intermFunctionCall)
+ , mArgumentNumber(argumentNumber) {}
+ virtual ~TGraphArgument() {}
+ const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
+ int getArgumentNumber() const { return mArgumentNumber; }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+private:
+ int mArgumentNumber;
+};
+
+//
+// Handle function calls.
+//
+class TGraphFunctionCall : public TGraphParentNode {
+public:
+ TGraphFunctionCall(TIntermAggregate* intermFunctionCall)
+ : TGraphParentNode(intermFunctionCall) {}
+ virtual ~TGraphFunctionCall() {}
+ const TIntermAggregate* getIntermFunctionCall() const { return intermNode->getAsAggregate(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle symbols.
+//
+class TGraphSymbol : public TGraphParentNode {
+public:
+ TGraphSymbol(TIntermSymbol* intermSymbol) : TGraphParentNode(intermSymbol) {}
+ virtual ~TGraphSymbol() {}
+ const TIntermSymbol* getIntermSymbol() const { return intermNode->getAsSymbolNode(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle if statements and ternary operators.
+//
+class TGraphSelection : public TGraphNode {
+public:
+ TGraphSelection(TIntermSelection* intermSelection) : TGraphNode(intermSelection) {}
+ virtual ~TGraphSelection() {}
+ const TIntermSelection* getIntermSelection() const { return intermNode->getAsSelectionNode(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+class TGraphLoop : public TGraphNode {
+public:
+ TGraphLoop(TIntermLoop* intermLoop) : TGraphNode(intermLoop) {}
+ virtual ~TGraphLoop() {}
+ const TIntermLoop* getIntermLoop() const { return intermNode->getAsLoopNode(); }
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// Handle logical and, or.
+//
+class TGraphLogicalOp : public TGraphNode {
+public:
+ TGraphLogicalOp(TIntermBinary* intermLogicalOp) : TGraphNode(intermLogicalOp) {}
+ virtual ~TGraphLogicalOp() {}
+ const TIntermBinary* getIntermLogicalOp() const { return intermNode->getAsBinaryNode(); }
+ const char* getOpString() const;
+ virtual void traverse(TDependencyGraphTraverser* graphTraverser);
+};
+
+//
+// A dependency graph of symbols, function calls, conditions etc.
+//
+// This class provides an interface to the entry points of the dependency graph.
+//
+// Dependency graph nodes should be created by using one of the provided "create..." methods.
+// This class (and nobody else) manages the memory of the created nodes.
+// Nodes may not be removed after being added, so all created nodes will exist while the
+// TDependencyGraph instance exists.
+//
+class TDependencyGraph {
+public:
+ TDependencyGraph(TIntermNode* intermNode);
+ ~TDependencyGraph();
+ TGraphNodeVector::const_iterator begin() const { return mAllNodes.begin(); }
+ TGraphNodeVector::const_iterator end() const { return mAllNodes.end(); }
+
+ TGraphSymbolVector::const_iterator beginSamplerSymbols() const
+ {
+ return mSamplerSymbols.begin();
+ }
+
+ TGraphSymbolVector::const_iterator endSamplerSymbols() const
+ {
+ return mSamplerSymbols.end();
+ }
+
+ TFunctionCallVector::const_iterator beginUserDefinedFunctionCalls() const
+ {
+ return mUserDefinedFunctionCalls.begin();
+ }
+
+ TFunctionCallVector::const_iterator endUserDefinedFunctionCalls() const
+ {
+ return mUserDefinedFunctionCalls.end();
+ }
+
+ TGraphArgument* createArgument(TIntermAggregate* intermFunctionCall, int argumentNumber);
+ TGraphFunctionCall* createFunctionCall(TIntermAggregate* intermFunctionCall);
+ TGraphSymbol* getOrCreateSymbol(TIntermSymbol* intermSymbol);
+ TGraphSelection* createSelection(TIntermSelection* intermSelection);
+ TGraphLoop* createLoop(TIntermLoop* intermLoop);
+ TGraphLogicalOp* createLogicalOp(TIntermBinary* intermLogicalOp);
+private:
+ typedef TMap<int, TGraphSymbol*> TSymbolIdMap;
+ typedef std::pair<int, TGraphSymbol*> TSymbolIdPair;
+
+ TGraphNodeVector mAllNodes;
+ TGraphSymbolVector mSamplerSymbols;
+ TFunctionCallVector mUserDefinedFunctionCalls;
+ TSymbolIdMap mSymbolIdMap;
+};
+
+//
+// For traversing the dependency graph. Users should derive from this,
+// put their traversal specific data in it, and then pass it to a
+// traverse method.
+//
+// When using this, just fill in the methods for nodes you want visited.
+//
+class TDependencyGraphTraverser {
+public:
+ TDependencyGraphTraverser() : mDepth(0) {}
+
+ virtual void visitSymbol(TGraphSymbol* symbol) {};
+ virtual void visitArgument(TGraphArgument* selection) {};
+ virtual void visitFunctionCall(TGraphFunctionCall* functionCall) {};
+ virtual void visitSelection(TGraphSelection* selection) {};
+ virtual void visitLoop(TGraphLoop* loop) {};
+ virtual void visitLogicalOp(TGraphLogicalOp* logicalOp) {};
+
+ int getDepth() const { return mDepth; }
+ void incrementDepth() { ++mDepth; }
+ void decrementDepth() { --mDepth; }
+
+ void clearVisited() { mVisited.clear(); }
+ void markVisited(TGraphNode* node) { mVisited.insert(node); }
+ bool isVisited(TGraphNode* node) const { return mVisited.find(node) != mVisited.end(); }
+private:
+ int mDepth;
+ TGraphNodeSet mVisited;
+};
+
+#endif
diff --git a/src/compiler/depgraph/DependencyGraphBuilder.cpp b/src/compiler/depgraph/DependencyGraphBuilder.cpp
new file mode 100644
index 00000000..d586cfd0
--- /dev/null
+++ b/src/compiler/depgraph/DependencyGraphBuilder.cpp
@@ -0,0 +1,227 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/depgraph/DependencyGraphBuilder.h"
+
+void TDependencyGraphBuilder::build(TIntermNode* node, TDependencyGraph* graph)
+{
+ TDependencyGraphBuilder builder(graph);
+ builder.build(node);
+}
+
+bool TDependencyGraphBuilder::visitAggregate(Visit visit, TIntermAggregate* intermAggregate)
+{
+ switch (intermAggregate->getOp()) {
+ case EOpFunction: visitFunctionDefinition(intermAggregate); break;
+ case EOpFunctionCall: visitFunctionCall(intermAggregate); break;
+ default: visitAggregateChildren(intermAggregate); break;
+ }
+
+ return false;
+}
+
+void TDependencyGraphBuilder::visitFunctionDefinition(TIntermAggregate* intermAggregate)
+{
+ // Currently, we do not support user defined functions.
+ if (intermAggregate->getName() != "main(")
+ return;
+
+ visitAggregateChildren(intermAggregate);
+}
+
+// Takes an expression like "f(x)" and creates a dependency graph like
+// "x -> argument 0 -> function call".
+void TDependencyGraphBuilder::visitFunctionCall(TIntermAggregate* intermFunctionCall)
+{
+ TGraphFunctionCall* functionCall = mGraph->createFunctionCall(intermFunctionCall);
+
+ // Run through the function call arguments.
+ int argumentNumber = 0;
+ TIntermSequence& intermArguments = intermFunctionCall->getSequence();
+ for (TIntermSequence::const_iterator iter = intermArguments.begin();
+ iter != intermArguments.end();
+ ++iter, ++argumentNumber)
+ {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ TIntermNode* intermArgument = *iter;
+ intermArgument->traverse(this);
+
+ if (TParentNodeSet* argumentNodes = mNodeSets.getTopSet()) {
+ TGraphArgument* argument = mGraph->createArgument(intermFunctionCall, argumentNumber);
+ connectMultipleNodesToSingleNode(argumentNodes, argument);
+ argument->addDependentNode(functionCall);
+ }
+ }
+
+ // Push the leftmost symbol of this function call into the current set of dependent symbols to
+ // represent the result of this function call.
+ // Thus, an expression like "y = f(x)" will yield a dependency graph like
+ // "x -> argument 0 -> function call -> y".
+ // This line essentially passes the function call node back up to an earlier visitAssignment
+ // call, which will create the connection "function call -> y".
+ mNodeSets.insertIntoTopSet(functionCall);
+}
+
+void TDependencyGraphBuilder::visitAggregateChildren(TIntermAggregate* intermAggregate)
+{
+ TIntermSequence& sequence = intermAggregate->getSequence();
+ for(TIntermSequence::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter)
+ {
+ TIntermNode* intermChild = *iter;
+ intermChild->traverse(this);
+ }
+}
+
+void TDependencyGraphBuilder::visitSymbol(TIntermSymbol* intermSymbol)
+{
+ // Push this symbol into the set of dependent symbols for the current assignment or condition
+ // that we are traversing.
+ TGraphSymbol* symbol = mGraph->getOrCreateSymbol(intermSymbol);
+ mNodeSets.insertIntoTopSet(symbol);
+
+ // If this symbol is the current leftmost symbol under an assignment, replace the previous
+ // leftmost symbol with this symbol.
+ if (!mLeftmostSymbols.empty() && mLeftmostSymbols.top() != &mRightSubtree) {
+ mLeftmostSymbols.pop();
+ mLeftmostSymbols.push(symbol);
+ }
+}
+
+bool TDependencyGraphBuilder::visitBinary(Visit visit, TIntermBinary* intermBinary)
+{
+ TOperator op = intermBinary->getOp();
+ if (op == EOpInitialize || intermBinary->modifiesState())
+ visitAssignment(intermBinary);
+ else if (op == EOpLogicalAnd || op == EOpLogicalOr)
+ visitLogicalOp(intermBinary);
+ else
+ visitBinaryChildren(intermBinary);
+
+ return false;
+}
+
+void TDependencyGraphBuilder::visitAssignment(TIntermBinary* intermAssignment)
+{
+ TIntermTyped* intermLeft = intermAssignment->getLeft();
+ if (!intermLeft)
+ return;
+
+ TGraphSymbol* leftmostSymbol = NULL;
+
+ {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mLeftSubtree);
+ intermLeft->traverse(this);
+ leftmostSymbol = mLeftmostSymbols.top();
+
+ // After traversing the left subtree of this assignment, we should have found a real
+ // leftmost symbol, and the leftmost symbol should not be a placeholder.
+ ASSERT(leftmostSymbol != &mLeftSubtree);
+ ASSERT(leftmostSymbol != &mRightSubtree);
+ }
+
+ if (TIntermTyped* intermRight = intermAssignment->getRight()) {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
+ intermRight->traverse(this);
+ }
+
+ if (TParentNodeSet* assignmentNodes = mNodeSets.getTopSet())
+ connectMultipleNodesToSingleNode(assignmentNodes, leftmostSymbol);
+ }
+
+ // Push the leftmost symbol of this assignment into the current set of dependent symbols to
+ // represent the result of this assignment.
+ // An expression like "a = (b = c)" will yield a dependency graph like "c -> b -> a".
+ // This line essentially passes the leftmost symbol of the nested assignment ("b" in this
+ // example) back up to the earlier visitAssignment call for the outer assignment, which will
+ // create the connection "b -> a".
+ mNodeSets.insertIntoTopSet(leftmostSymbol);
+}
+
+void TDependencyGraphBuilder::visitLogicalOp(TIntermBinary* intermLogicalOp)
+{
+ if (TIntermTyped* intermLeft = intermLogicalOp->getLeft()) {
+ TNodeSetPropagatingMaintainer nodeSetMaintainer(this);
+
+ intermLeft->traverse(this);
+ if (TParentNodeSet* leftNodes = mNodeSets.getTopSet()) {
+ TGraphLogicalOp* logicalOp = mGraph->createLogicalOp(intermLogicalOp);
+ connectMultipleNodesToSingleNode(leftNodes, logicalOp);
+ }
+ }
+
+ if (TIntermTyped* intermRight = intermLogicalOp->getRight()) {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
+ intermRight->traverse(this);
+ }
+}
+
+void TDependencyGraphBuilder::visitBinaryChildren(TIntermBinary* intermBinary)
+{
+ if (TIntermTyped* intermLeft = intermBinary->getLeft())
+ intermLeft->traverse(this);
+
+ if (TIntermTyped* intermRight = intermBinary->getRight()) {
+ TLeftmostSymbolMaintainer leftmostSymbolMaintainer(this, mRightSubtree);
+ intermRight->traverse(this);
+ }
+}
+
+bool TDependencyGraphBuilder::visitSelection(Visit visit, TIntermSelection* intermSelection)
+{
+ if (TIntermNode* intermCondition = intermSelection->getCondition()) {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ intermCondition->traverse(this);
+ if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
+ TGraphSelection* selection = mGraph->createSelection(intermSelection);
+ connectMultipleNodesToSingleNode(conditionNodes, selection);
+ }
+ }
+
+ if (TIntermNode* intermTrueBlock = intermSelection->getTrueBlock())
+ intermTrueBlock->traverse(this);
+
+ if (TIntermNode* intermFalseBlock = intermSelection->getFalseBlock())
+ intermFalseBlock->traverse(this);
+
+ return false;
+}
+
+bool TDependencyGraphBuilder::visitLoop(Visit visit, TIntermLoop* intermLoop)
+{
+ if (TIntermTyped* intermCondition = intermLoop->getCondition()) {
+ TNodeSetMaintainer nodeSetMaintainer(this);
+
+ intermCondition->traverse(this);
+ if (TParentNodeSet* conditionNodes = mNodeSets.getTopSet()) {
+ TGraphLoop* loop = mGraph->createLoop(intermLoop);
+ connectMultipleNodesToSingleNode(conditionNodes, loop);
+ }
+ }
+
+ if (TIntermNode* intermBody = intermLoop->getBody())
+ intermBody->traverse(this);
+
+ if (TIntermTyped* intermExpression = intermLoop->getExpression())
+ intermExpression->traverse(this);
+
+ return false;
+}
+
+
+void TDependencyGraphBuilder::connectMultipleNodesToSingleNode(TParentNodeSet* nodes,
+ TGraphNode* node) const
+{
+ for (TParentNodeSet::const_iterator iter = nodes->begin(); iter != nodes->end(); ++iter)
+ {
+ TGraphParentNode* currentNode = *iter;
+ currentNode->addDependentNode(node);
+ }
+}
diff --git a/src/compiler/depgraph/DependencyGraphBuilder.h b/src/compiler/depgraph/DependencyGraphBuilder.h
new file mode 100644
index 00000000..c5f232cb
--- /dev/null
+++ b/src/compiler/depgraph/DependencyGraphBuilder.h
@@ -0,0 +1,181 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
+#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
+
+#include "compiler/depgraph/DependencyGraph.h"
+
+//
+// Creates a dependency graph of symbols, function calls, conditions etc. by traversing a
+// intermediate tree.
+//
+class TDependencyGraphBuilder : public TIntermTraverser {
+public:
+ static void build(TIntermNode* node, TDependencyGraph* graph);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual bool visitBinary(Visit visit, TIntermBinary*);
+ virtual bool visitSelection(Visit visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit visit, TIntermLoop*);
+
+private:
+ typedef std::stack<TGraphSymbol*> TSymbolStack;
+ typedef std::set<TGraphParentNode*> TParentNodeSet;
+
+ //
+ // For collecting the dependent nodes of assignments, conditions, etc.
+ // while traversing the intermediate tree.
+ //
+ // This data structure is stack of sets. Each set contains dependency graph parent nodes.
+ //
+ class TNodeSetStack {
+ public:
+ TNodeSetStack() {};
+ ~TNodeSetStack() { clear(); }
+
+ // This should only be called after a pushSet.
+ // Returns NULL if the top set is empty.
+ TParentNodeSet* getTopSet() const
+ {
+ ASSERT(!nodeSets.empty());
+ TParentNodeSet* topSet = nodeSets.top();
+ return !topSet->empty() ? topSet : NULL;
+ }
+
+ void pushSet() { nodeSets.push(new TParentNodeSet()); }
+ void popSet()
+ {
+ ASSERT(!nodeSets.empty());
+ delete nodeSets.top();
+ nodeSets.pop();
+ }
+
+ // Pops the top set and adds its contents to the new top set.
+ // This should only be called after a pushSet.
+ // If there is no set below the top set, the top set is just deleted.
+ void popSetIntoNext()
+ {
+ ASSERT(!nodeSets.empty());
+ TParentNodeSet* oldTopSet = nodeSets.top();
+ nodeSets.pop();
+
+ if (!nodeSets.empty()) {
+ TParentNodeSet* newTopSet = nodeSets.top();
+ newTopSet->insert(oldTopSet->begin(), oldTopSet->end());
+ }
+
+ delete oldTopSet;
+ }
+
+ // Does nothing if there is no top set.
+ // This can be called when there is no top set if we are visiting
+ // symbols that are not under an assignment or condition.
+ // We don't need to track those symbols.
+ void insertIntoTopSet(TGraphParentNode* node)
+ {
+ if (nodeSets.empty())
+ return;
+
+ nodeSets.top()->insert(node);
+ }
+
+ void clear()
+ {
+ while (!nodeSets.empty())
+ popSet();
+ }
+
+ private:
+ typedef std::stack<TParentNodeSet*> TParentNodeSetStack;
+
+ TParentNodeSetStack nodeSets;
+ };
+
+ //
+ // An instance of this class pushes a new node set when instantiated.
+ // When the instance goes out of scope, it and pops the node set.
+ //
+ class TNodeSetMaintainer {
+ public:
+ TNodeSetMaintainer(TDependencyGraphBuilder* factory)
+ : sets(factory->mNodeSets) { sets.pushSet(); }
+ ~TNodeSetMaintainer() { sets.popSet(); }
+ protected:
+ TNodeSetStack& sets;
+ };
+
+ //
+ // An instance of this class pushes a new node set when instantiated.
+ // When the instance goes out of scope, it and pops the top node set and adds its contents to
+ // the new top node set.
+ //
+ class TNodeSetPropagatingMaintainer {
+ public:
+ TNodeSetPropagatingMaintainer(TDependencyGraphBuilder* factory)
+ : sets(factory->mNodeSets) { sets.pushSet(); }
+ ~TNodeSetPropagatingMaintainer() { sets.popSetIntoNext(); }
+ protected:
+ TNodeSetStack& sets;
+ };
+
+ //
+ // An instance of this class keeps track of the leftmost symbol while we're exploring an
+ // assignment.
+ // It will push the placeholder symbol kLeftSubtree when instantiated under a left subtree,
+ // and kRightSubtree under a right subtree.
+ // When it goes out of scope, it will pop the leftmost symbol at the top of the scope.
+ // During traversal, the TDependencyGraphBuilder will replace kLeftSubtree with a real symbol.
+ // kRightSubtree will never be replaced by a real symbol because we are tracking the leftmost
+ // symbol.
+ //
+ class TLeftmostSymbolMaintainer {
+ public:
+ TLeftmostSymbolMaintainer(TDependencyGraphBuilder* factory, TGraphSymbol& subtree)
+ : leftmostSymbols(factory->mLeftmostSymbols)
+ {
+ needsPlaceholderSymbol = leftmostSymbols.empty() || leftmostSymbols.top() != &subtree;
+ if (needsPlaceholderSymbol)
+ leftmostSymbols.push(&subtree);
+ }
+
+ ~TLeftmostSymbolMaintainer()
+ {
+ if (needsPlaceholderSymbol)
+ leftmostSymbols.pop();
+ }
+
+ protected:
+ TSymbolStack& leftmostSymbols;
+ bool needsPlaceholderSymbol;
+ };
+
+ TDependencyGraphBuilder(TDependencyGraph* graph)
+ : TIntermTraverser(true, false, false)
+ , mLeftSubtree(NULL)
+ , mRightSubtree(NULL)
+ , mGraph(graph) {}
+ void build(TIntermNode* intermNode) { intermNode->traverse(this); }
+
+ void connectMultipleNodesToSingleNode(TParentNodeSet* nodes, TGraphNode* node) const;
+
+ void visitAssignment(TIntermBinary*);
+ void visitLogicalOp(TIntermBinary*);
+ void visitBinaryChildren(TIntermBinary*);
+ void visitFunctionDefinition(TIntermAggregate*);
+ void visitFunctionCall(TIntermAggregate* intermFunctionCall);
+ void visitAggregateChildren(TIntermAggregate*);
+
+ TGraphSymbol mLeftSubtree;
+ TGraphSymbol mRightSubtree;
+
+ TDependencyGraph* mGraph;
+ TNodeSetStack mNodeSets;
+ TSymbolStack mLeftmostSymbols;
+};
+
+#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H
diff --git a/src/compiler/depgraph/DependencyGraphOutput.cpp b/src/compiler/depgraph/DependencyGraphOutput.cpp
new file mode 100644
index 00000000..6fc489e7
--- /dev/null
+++ b/src/compiler/depgraph/DependencyGraphOutput.cpp
@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/depgraph/DependencyGraphOutput.h"
+
+void TDependencyGraphOutput::outputIndentation()
+{
+ for (int i = 0; i < getDepth(); ++i)
+ mSink << " ";
+}
+
+void TDependencyGraphOutput::visitArgument(TGraphArgument* parameter)
+{
+ outputIndentation();
+ mSink << "argument " << parameter->getArgumentNumber() << " of call to "
+ << parameter->getIntermFunctionCall()->getName() << "\n";
+}
+
+void TDependencyGraphOutput::visitFunctionCall(TGraphFunctionCall* functionCall)
+{
+ outputIndentation();
+ mSink << "function call " << functionCall->getIntermFunctionCall()->getName() << "\n";
+}
+
+void TDependencyGraphOutput::visitSymbol(TGraphSymbol* symbol)
+{
+ outputIndentation();
+ mSink << symbol->getIntermSymbol()->getSymbol() << " (symbol id: "
+ << symbol->getIntermSymbol()->getId() << ")\n";
+}
+
+void TDependencyGraphOutput::visitSelection(TGraphSelection* selection)
+{
+ outputIndentation();
+ mSink << "selection\n";
+}
+
+void TDependencyGraphOutput::visitLoop(TGraphLoop* loop)
+{
+ outputIndentation();
+ mSink << "loop condition\n";
+}
+
+void TDependencyGraphOutput::visitLogicalOp(TGraphLogicalOp* logicalOp)
+{
+ outputIndentation();
+ mSink << "logical " << logicalOp->getOpString() << "\n";
+}
+
+void TDependencyGraphOutput::outputAllSpanningTrees(TDependencyGraph& graph)
+{
+ mSink << "\n";
+
+ for (TGraphNodeVector::const_iterator iter = graph.begin(); iter != graph.end(); ++iter)
+ {
+ TGraphNode* symbol = *iter;
+ mSink << "--- Dependency graph spanning tree ---\n";
+ clearVisited();
+ symbol->traverse(this);
+ mSink << "\n";
+ }
+}
diff --git a/src/compiler/depgraph/DependencyGraphOutput.h b/src/compiler/depgraph/DependencyGraphOutput.h
new file mode 100644
index 00000000..01447da9
--- /dev/null
+++ b/src/compiler/depgraph/DependencyGraphOutput.h
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
+#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
+
+#include "compiler/depgraph/DependencyGraph.h"
+#include "compiler/InfoSink.h"
+
+class TDependencyGraphOutput : public TDependencyGraphTraverser {
+public:
+ TDependencyGraphOutput(TInfoSinkBase& sink) : mSink(sink) {}
+ virtual void visitSymbol(TGraphSymbol* symbol);
+ virtual void visitArgument(TGraphArgument* parameter);
+ virtual void visitFunctionCall(TGraphFunctionCall* functionCall);
+ virtual void visitSelection(TGraphSelection* selection);
+ virtual void visitLoop(TGraphLoop* loop);
+ virtual void visitLogicalOp(TGraphLogicalOp* logicalOp);
+
+ void outputAllSpanningTrees(TDependencyGraph& graph);
+private:
+ void outputIndentation();
+
+ TInfoSinkBase& mSink;
+};
+
+#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H
diff --git a/src/compiler/depgraph/DependencyGraphTraverse.cpp b/src/compiler/depgraph/DependencyGraphTraverse.cpp
new file mode 100644
index 00000000..b158575c
--- /dev/null
+++ b/src/compiler/depgraph/DependencyGraphTraverse.cpp
@@ -0,0 +1,69 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/depgraph/DependencyGraph.h"
+
+// These methods do a breadth-first traversal through the graph and mark visited nodes.
+
+void TGraphNode::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->markVisited(this);
+}
+
+void TGraphParentNode::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ TGraphNode::traverse(graphTraverser);
+
+ graphTraverser->incrementDepth();
+
+ // Visit the parent node's children.
+ for (TGraphNodeSet::const_iterator iter = mDependentNodes.begin();
+ iter != mDependentNodes.end();
+ ++iter)
+ {
+ TGraphNode* node = *iter;
+ if (!graphTraverser->isVisited(node))
+ node->traverse(graphTraverser);
+ }
+
+ graphTraverser->decrementDepth();
+}
+
+void TGraphArgument::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitArgument(this);
+ TGraphParentNode::traverse(graphTraverser);
+}
+
+void TGraphFunctionCall::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitFunctionCall(this);
+ TGraphParentNode::traverse(graphTraverser);
+}
+
+void TGraphSymbol::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitSymbol(this);
+ TGraphParentNode::traverse(graphTraverser);
+}
+
+void TGraphSelection::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitSelection(this);
+ TGraphNode::traverse(graphTraverser);
+}
+
+void TGraphLoop::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitLoop(this);
+ TGraphNode::traverse(graphTraverser);
+}
+
+void TGraphLogicalOp::traverse(TDependencyGraphTraverser* graphTraverser)
+{
+ graphTraverser->visitLogicalOp(this);
+ TGraphNode::traverse(graphTraverser);
+}
diff --git a/src/compiler/generate_parser.sh b/src/compiler/generate_parser.sh
new file mode 100755
index 00000000..e4d88b2e
--- /dev/null
+++ b/src/compiler/generate_parser.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright (c) 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.
+
+# Generates GLSL ES parser - glslang_lex.cpp, glslang_tab.h, and glslang_tab.cpp
+
+run_flex()
+{
+input_file=$script_dir/$1.l
+output_source=$script_dir/$1_lex.cpp
+flex --noline --nounistd --outfile=$output_source $input_file
+}
+
+run_bison()
+{
+input_file=$script_dir/$1.y
+output_header=$script_dir/$1_tab.h
+output_source=$script_dir/$1_tab.cpp
+bison --no-lines --skeleton=yacc.c --defines=$output_header --output=$output_source $input_file
+}
+
+script_dir=$(dirname $0)
+
+# Generate Parser
+run_flex glslang
+run_bison glslang
+patch --silent --forward < 64bit-lexer-safety.patch
diff --git a/src/compiler/glslang.h b/src/compiler/glslang.h
new file mode 100644
index 00000000..f2211990
--- /dev/null
+++ b/src/compiler/glslang.h
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 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.
+//
+
+struct TParseContext;
+extern int glslang_initialize(TParseContext* context);
+extern int glslang_finalize(TParseContext* context);
+
+extern int glslang_scan(size_t count,
+ const char* const string[],
+ const int length[],
+ TParseContext* context);
+extern int glslang_parse(TParseContext* context);
+
diff --git a/src/compiler/glslang.l b/src/compiler/glslang.l
new file mode 100644
index 00000000..40498750
--- /dev/null
+++ b/src/compiler/glslang.l
@@ -0,0 +1,331 @@
+/*
+//
+// 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.
+//
+
+This file contains the Lex specification for GLSL ES.
+Based on ANSI C grammar, Lex specification:
+http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
+*/
+
+%top{
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+}
+
+%{
+#include "compiler/glslang.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/preprocessor/Token.h"
+#include "compiler/util.h"
+#include "glslang_tab.h"
+
+/* windows only pragma */
+#ifdef _MSC_VER
+#pragma warning(disable : 4102)
+#endif
+
+#define YY_USER_ACTION \
+ yylloc->first_file = yylloc->last_file = yycolumn; \
+ yylloc->first_line = yylloc->last_line = yylineno;
+
+#define YY_INPUT(buf, result, max_size) \
+ result = string_input(buf, max_size, yyscanner);
+
+static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner);
+static int check_type(yyscan_t yyscanner);
+static int reserved_word(yyscan_t yyscanner);
+%}
+
+%option noyywrap nounput never-interactive
+%option yylineno reentrant bison-bridge bison-locations
+%option extra-type="TParseContext*"
+
+D [0-9]
+L [a-zA-Z_]
+H [a-fA-F0-9]
+E [Ee][+-]?{D}+
+O [0-7]
+
+%%
+
+"invariant" { return INVARIANT; }
+"highp" { return HIGH_PRECISION; }
+"mediump" { return MEDIUM_PRECISION; }
+"lowp" { return LOW_PRECISION; }
+"precision" { return PRECISION; }
+
+"attribute" { return ATTRIBUTE; }
+"const" { return CONST_QUAL; }
+"uniform" { return UNIFORM; }
+"varying" { return VARYING; }
+
+"break" { return BREAK; }
+"continue" { return CONTINUE; }
+"do" { return DO; }
+"for" { return FOR; }
+"while" { return WHILE; }
+
+"if" { return IF; }
+"else" { return ELSE; }
+
+"in" { return IN_QUAL; }
+"out" { return OUT_QUAL; }
+"inout" { return INOUT_QUAL; }
+
+"float" { return FLOAT_TYPE; }
+"int" { return INT_TYPE; }
+"void" { return VOID_TYPE; }
+"bool" { return BOOL_TYPE; }
+"true" { yylval->lex.b = true; return BOOLCONSTANT; }
+"false" { yylval->lex.b = false; return BOOLCONSTANT; }
+
+"discard" { return DISCARD; }
+"return" { return RETURN; }
+
+"mat2" { return MATRIX2; }
+"mat3" { return MATRIX3; }
+"mat4" { return MATRIX4; }
+
+"vec2" { return VEC2; }
+"vec3" { return VEC3; }
+"vec4" { return VEC4; }
+"ivec2" { return IVEC2; }
+"ivec3" { return IVEC3; }
+"ivec4" { return IVEC4; }
+"bvec2" { return BVEC2; }
+"bvec3" { return BVEC3; }
+"bvec4" { return BVEC4; }
+
+"sampler2D" { return SAMPLER2D; }
+"samplerCube" { return SAMPLERCUBE; }
+"samplerExternalOES" { return SAMPLER_EXTERNAL_OES; }
+"sampler2DRect" { return SAMPLER2DRECT; }
+
+"struct" { return STRUCT; }
+
+"asm" { return reserved_word(yyscanner); }
+
+"class" { return reserved_word(yyscanner); }
+"union" { return reserved_word(yyscanner); }
+"enum" { return reserved_word(yyscanner); }
+"typedef" { return reserved_word(yyscanner); }
+"template" { return reserved_word(yyscanner); }
+"this" { return reserved_word(yyscanner); }
+"packed" { return reserved_word(yyscanner); }
+
+"goto" { return reserved_word(yyscanner); }
+"switch" { return reserved_word(yyscanner); }
+"default" { return reserved_word(yyscanner); }
+
+"inline" { return reserved_word(yyscanner); }
+"noinline" { return reserved_word(yyscanner); }
+"volatile" { return reserved_word(yyscanner); }
+"public" { return reserved_word(yyscanner); }
+"static" { return reserved_word(yyscanner); }
+"extern" { return reserved_word(yyscanner); }
+"external" { return reserved_word(yyscanner); }
+"interface" { return reserved_word(yyscanner); }
+"flat" { return reserved_word(yyscanner); }
+
+"long" { return reserved_word(yyscanner); }
+"short" { return reserved_word(yyscanner); }
+"double" { return reserved_word(yyscanner); }
+"half" { return reserved_word(yyscanner); }
+"fixed" { return reserved_word(yyscanner); }
+"unsigned" { return reserved_word(yyscanner); }
+"superp" { return reserved_word(yyscanner); }
+
+"input" { return reserved_word(yyscanner); }
+"output" { return reserved_word(yyscanner); }
+
+"hvec2" { return reserved_word(yyscanner); }
+"hvec3" { return reserved_word(yyscanner); }
+"hvec4" { return reserved_word(yyscanner); }
+"dvec2" { return reserved_word(yyscanner); }
+"dvec3" { return reserved_word(yyscanner); }
+"dvec4" { return reserved_word(yyscanner); }
+"fvec2" { return reserved_word(yyscanner); }
+"fvec3" { return reserved_word(yyscanner); }
+"fvec4" { return reserved_word(yyscanner); }
+
+"sampler1D" { return reserved_word(yyscanner); }
+"sampler3D" { return reserved_word(yyscanner); }
+"sampler1DShadow" { return reserved_word(yyscanner); }
+"sampler2DShadow" { return reserved_word(yyscanner); }
+"sampler3DRect" { return reserved_word(yyscanner); }
+"sampler2DRectShadow" { return reserved_word(yyscanner); }
+
+"sizeof" { return reserved_word(yyscanner); }
+"cast" { return reserved_word(yyscanner); }
+
+"namespace" { return reserved_word(yyscanner); }
+"using" { return reserved_word(yyscanner); }
+
+{L}({L}|{D})* {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+}
+
+0[xX]{H}+ { yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+0{O}+ { yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+{D}+ { yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+
+{D}+{E} { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+{D}+"."{D}*({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+"."{D}+({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+
+"+=" { return ADD_ASSIGN; }
+"-=" { return SUB_ASSIGN; }
+"*=" { return MUL_ASSIGN; }
+"/=" { return DIV_ASSIGN; }
+"%=" { return MOD_ASSIGN; }
+"<<=" { return LEFT_ASSIGN; }
+">>=" { return RIGHT_ASSIGN; }
+"&=" { return AND_ASSIGN; }
+"^=" { return XOR_ASSIGN; }
+"|=" { return OR_ASSIGN; }
+
+"++" { return INC_OP; }
+"--" { return DEC_OP; }
+"&&" { return AND_OP; }
+"||" { return OR_OP; }
+"^^" { return XOR_OP; }
+"<=" { return LE_OP; }
+">=" { return GE_OP; }
+"==" { return EQ_OP; }
+"!=" { return NE_OP; }
+"<<" { return LEFT_OP; }
+">>" { return RIGHT_OP; }
+";" { return SEMICOLON; }
+("{"|"<%") { return LEFT_BRACE; }
+("}"|"%>") { return RIGHT_BRACE; }
+"," { return COMMA; }
+":" { return COLON; }
+"=" { return EQUAL; }
+"(" { return LEFT_PAREN; }
+")" { return RIGHT_PAREN; }
+("["|"<:") { return LEFT_BRACKET; }
+("]"|":>") { return RIGHT_BRACKET; }
+"." { return DOT; }
+"!" { return BANG; }
+"-" { return DASH; }
+"~" { return TILDE; }
+"+" { return PLUS; }
+"*" { return STAR; }
+"/" { return SLASH; }
+"%" { return PERCENT; }
+"<" { return LEFT_ANGLE; }
+">" { return RIGHT_ANGLE; }
+"|" { return VERTICAL_BAR; }
+"^" { return CARET; }
+"&" { return AMPERSAND; }
+"?" { return QUESTION; }
+
+[ \t\v\n\f\r] { }
+<<EOF>> { yyterminate(); }
+. { assert(false); return 0; }
+
+%%
+
+yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) {
+ pp::Token token;
+ yyget_extra(yyscanner)->preprocessor.lex(&token);
+ yy_size_t len = token.type == pp::Token::LAST ? 0 : token.text.size();
+ if (len < max_size)
+ memcpy(buf, token.text.c_str(), len);
+ yyset_column(token.location.file, yyscanner);
+ yyset_lineno(token.location.line, yyscanner);
+
+ if (len >= max_size)
+ YY_FATAL_ERROR("Input buffer overflow");
+ else if (len > 0)
+ buf[len++] = ' ';
+ return len;
+}
+
+int check_type(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ int token = IDENTIFIER;
+ TSymbol* symbol = yyextra->symbolTable.find(yytext);
+ if (symbol && symbol->isVariable()) {
+ TVariable* variable = static_cast<TVariable*>(symbol);
+ if (variable->isUserType())
+ token = TYPE_NAME;
+ }
+ yylval->lex.symbol = symbol;
+ return token;
+}
+
+int reserved_word(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ yyextra->error(*yylloc, "Illegal use of reserved word", yytext, "");
+ yyextra->recover();
+ return 0;
+}
+
+int glslang_initialize(TParseContext* context) {
+ yyscan_t scanner = NULL;
+ if (yylex_init_extra(context, &scanner))
+ return 1;
+
+ context->scanner = scanner;
+ return 0;
+}
+
+int glslang_finalize(TParseContext* context) {
+ yyscan_t scanner = context->scanner;
+ if (scanner == NULL) return 0;
+
+ context->scanner = NULL;
+ yylex_destroy(scanner);
+
+ return 0;
+}
+
+int glslang_scan(size_t count, const char* const string[], const int length[],
+ TParseContext* context) {
+ yyrestart(NULL, context->scanner);
+ yyset_column(0, context->scanner);
+ yyset_lineno(1, context->scanner);
+
+ // Initialize preprocessor.
+ if (!context->preprocessor.init(count, string, length))
+ return 1;
+
+ // Define extension macros.
+ const TExtensionBehavior& extBehavior = context->extensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
+ iter != extBehavior.end(); ++iter) {
+ context->preprocessor.predefineMacro(iter->first.c_str(), 1);
+ }
+ if (context->fragmentPrecisionHigh)
+ context->preprocessor.predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ return 0;
+}
+
diff --git a/src/compiler/glslang.y b/src/compiler/glslang.y
new file mode 100644
index 00000000..0e8c3c3b
--- /dev/null
+++ b/src/compiler/glslang.y
@@ -0,0 +1,2014 @@
+/*
+//
+// 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.
+//
+
+This file contains the Yacc grammar for GLSL ES.
+Based on ANSI C Yacc grammar:
+http://www.lysator.liu.se/c/ANSI-C-grammar-y.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
+*/
+
+%{
+//
+// 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.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+
+#include "compiler/SymbolTable.h"
+#include "compiler/ParseHelper.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYENABLE_NLS 0
+
+#define YYLEX_PARAM context->scanner
+%}
+
+%expect 1 /* One shift reduce conflict because of if | else */
+%pure-parser
+%parse-param {TParseContext* context}
+%locations
+
+%code requires {
+#define YYLTYPE TSourceLoc
+#define YYLTYPE_IS_DECLARED 1
+}
+
+%union {
+ struct {
+ union {
+ TString *string;
+ float f;
+ int i;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TField* field;
+ TFieldList* fieldList;
+ };
+ } interm;
+}
+
+%{
+extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner);
+static void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason);
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (YYID(N)) { \
+ (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).last_file = YYRHSLOC(Rhs, N).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ } \
+ else { \
+ (Current).first_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \
+ (Current).last_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, 0).last_line; \
+ } \
+ } while (0)
+
+#define VERTEX_ONLY(S, L) { \
+ if (context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define FRAG_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER) { \
+ context->error(L, " supported in fragment shaders only ", S); \
+ context->recover(); \
+ } \
+}
+%}
+
+%token <lex> INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION
+%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE
+%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN
+%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4
+%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING
+%token <lex> STRUCT VOID_TYPE WHILE
+%token <lex> SAMPLER2D SAMPLERCUBE SAMPLER_EXTERNAL_OES SAMPLER2DRECT
+
+%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT BOOLCONSTANT
+%token <lex> LEFT_OP RIGHT_OP
+%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
+%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
+%token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
+%token <lex> SUB_ASSIGN
+
+%token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT
+%token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT
+%token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION
+
+%type <lex> identifier
+%type <interm> assignment_operator unary_operator
+%type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression
+%type <interm.intermTypedNode> expression integer_expression assignment_expression
+%type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression
+%type <interm.intermTypedNode> relational_expression equality_expression
+%type <interm.intermTypedNode> conditional_expression constant_expression
+%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression
+%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression
+%type <interm.intermTypedNode> function_call initializer condition conditionopt
+
+%type <interm.intermNode> translation_unit function_definition
+%type <interm.intermNode> statement simple_statement
+%type <interm.intermAggregate> statement_list compound_statement
+%type <interm.intermNode> declaration_statement selection_statement expression_statement
+%type <interm.intermNode> declaration external_declaration
+%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
+%type <interm.nodePair> selection_rest_statement for_rest_statement
+%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_with_scope
+%type <interm> single_declaration init_declarator_list
+
+%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
+%type <interm.qualifier> parameter_qualifier
+
+%type <interm.precision> precision_qualifier
+%type <interm.type> type_qualifier fully_specified_type type_specifier
+%type <interm.type> type_specifier_no_prec type_specifier_nonarray
+%type <interm.type> struct_specifier
+%type <interm.field> struct_declarator
+%type <interm.fieldList> struct_declarator_list struct_declaration struct_declaration_list
+%type <interm.function> function_header function_declarator function_identifier
+%type <interm.function> function_header_with_parameters function_call_header
+%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype
+%type <interm> function_call_or_method
+
+%start translation_unit
+%%
+
+identifier
+ : IDENTIFIER
+ | TYPE_NAME
+
+variable_identifier
+ : IDENTIFIER {
+ // The symbol table search was done in the lexical phase
+ const TSymbol* symbol = $1.symbol;
+ const TVariable* variable;
+ if (symbol == 0) {
+ context->error(@1, "undeclared identifier", $1.string->c_str());
+ context->recover();
+ TType type(EbtFloat, EbpUndefined);
+ TVariable* fakeVariable = new TVariable($1.string, type);
+ context->symbolTable.insert(*fakeVariable);
+ variable = fakeVariable;
+ } else {
+ // This identifier can only be a variable type symbol
+ if (! symbol->isVariable()) {
+ context->error(@1, "variable expected", $1.string->c_str());
+ context->recover();
+ }
+
+ variable = static_cast<const TVariable*>(symbol);
+
+ if (context->symbolTable.findBuiltIn(variable->getName()) &&
+ !variable->getExtension().empty() &&
+ context->extensionErrorCheck(@1, variable->getExtension())) {
+ context->recover();
+ }
+ }
+
+ // don't delete $1.string, it's used by error recovery, and the pool
+ // pop will reclaim the memory
+
+ if (variable->getType().getQualifier() == EvqConst ) {
+ ConstantUnion* constArray = variable->getConstPointer();
+ TType t(variable->getType());
+ $$ = context->intermediate.addConstantUnion(constArray, t, @1);
+ } else
+ $$ = context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(),
+ @1);
+ }
+ ;
+
+primary_expression
+ : variable_identifier {
+ $$ = $1;
+ }
+ | INTCONSTANT {
+ //
+ // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders,
+ // check for overflow for constants
+ //
+ if (abs($1.i) >= (1 << 16)) {
+ context->error(@1, " integer constant overflow", "");
+ context->recover();
+ }
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst($1.i);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @1);
+ }
+ | FLOATCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst($1.f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1);
+ }
+ | BOOLCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst($1.b);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @1);
+ }
+ | LEFT_PAREN expression RIGHT_PAREN {
+ $$ = $2;
+ }
+ ;
+
+postfix_expression
+ : primary_expression {
+ $$ = $1;
+ }
+ | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET {
+ $$ = context->addIndexExpression($1, @2, $3);
+ }
+ | function_call {
+ $$ = $1;
+ }
+ | postfix_expression DOT identifier {
+ if ($1->isArray()) {
+ context->error(@3, "cannot apply dot operator to an array", ".");
+ context->recover();
+ }
+
+ if ($1->isVector()) {
+ TVectorFields fields;
+ if (! context->parseVectorFields(*$3.string, $1->getNominalSize(), fields, @3)) {
+ fields.num = 1;
+ fields.offsets[0] = 0;
+ context->recover();
+ }
+
+ if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields
+ $$ = context->addConstVectorNode(fields, $1, @3);
+ if ($$ == 0) {
+ context->recover();
+ $$ = $1;
+ }
+ else
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, (int) (*$3.string).size()));
+ } else {
+ TString vectorString = *$3.string;
+ TIntermTyped* index = context->intermediate.addSwizzle(fields, @3);
+ $$ = context->intermediate.addIndex(EOpVectorSwizzle, $1, index, @2);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, (int) vectorString.size()));
+ }
+ } else if ($1->isMatrix()) {
+ TMatrixFields fields;
+ if (! context->parseMatrixFields(*$3.string, $1->getNominalSize(), fields, @3)) {
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = 0;
+ fields.col = 0;
+ context->recover();
+ }
+
+ if (fields.wholeRow || fields.wholeCol) {
+ context->error(@2, " non-scalar fields not implemented yet", ".");
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(0);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @3);
+ $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, @2);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(),EvqTemporary, $1->getNominalSize()));
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), @3);
+ $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, @2);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision()));
+ }
+ } else if ($1->getBasicType() == EbtStruct) {
+ bool fieldFound = false;
+ const TFieldList& fields = $1->getType().getStruct()->fields();
+ unsigned int i;
+ for (i = 0; i < fields.size(); ++i) {
+ if (fields[i]->name() == *$3.string) {
+ fieldFound = true;
+ break;
+ }
+ }
+ if (fieldFound) {
+ if ($1->getType().getQualifier() == EvqConst) {
+ $$ = context->addConstStruct(*$3.string, $1, @2);
+ if ($$ == 0) {
+ context->recover();
+ $$ = $1;
+ }
+ else {
+ $$->setType(*fields[i]->type());
+ // change the qualifier of the return type, not of the structure field
+ // as the structure definition is shared between various structures.
+ $$->getTypePointer()->setQualifier(EvqConst);
+ }
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(i);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *fields[i]->type(), @3);
+ $$ = context->intermediate.addIndex(EOpIndexDirectStruct, $1, index, @2);
+ $$->setType(*fields[i]->type());
+ }
+ } else {
+ context->error(@2, " no such field in structure", $3.string->c_str());
+ context->recover();
+ $$ = $1;
+ }
+ } else {
+ context->error(@2, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str());
+ context->recover();
+ $$ = $1;
+ }
+ // don't delete $3.string, it's from the pool
+ }
+ | postfix_expression INC_OP {
+ if (context->lValueErrorCheck(@2, "++", $1))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError(@2, "++", $1->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | postfix_expression DEC_OP {
+ if (context->lValueErrorCheck(@2, "--", $1))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError(@2, "--", $1->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+integer_expression
+ : expression {
+ if (context->integerErrorCheck($1, "[]"))
+ context->recover();
+ $$ = $1;
+ }
+ ;
+
+function_call
+ : function_call_or_method {
+ TFunction* fnCall = $1.function;
+ TOperator op = fnCall->getBuiltInOp();
+
+ if (op != EOpNull)
+ {
+ //
+ // Then this should be a constructor.
+ // Don't go through the symbol table for constructors.
+ // Their parameters will be verified algorithmically.
+ //
+ TType type(EbtVoid, EbpUndefined); // use this to get the type back
+ if (context->constructorErrorCheck(@1, $1.intermNode, *fnCall, op, &type)) {
+ $$ = 0;
+ } else {
+ //
+ // It's a constructor, of type 'type'.
+ //
+ $$ = context->addConstructor($1.intermNode, &type, op, fnCall, @1);
+ }
+
+ if ($$ == 0) {
+ context->recover();
+ $$ = context->intermediate.setAggregateOperator(0, op, @1);
+ }
+ $$->setType(type);
+ } else {
+ //
+ // Not a constructor. Find it in the symbol table.
+ //
+ const TFunction* fnCandidate;
+ bool builtIn;
+ fnCandidate = context->findFunction(@1, fnCall, &builtIn);
+ if (fnCandidate) {
+ //
+ // A declared function.
+ //
+ if (builtIn && !fnCandidate->getExtension().empty() &&
+ context->extensionErrorCheck(@1, fnCandidate->getExtension())) {
+ context->recover();
+ }
+ op = fnCandidate->getBuiltInOp();
+ if (builtIn && op != EOpNull) {
+ //
+ // A function call mapped to a built-in operation.
+ //
+ if (fnCandidate->getParamCount() == 1) {
+ //
+ // Treat it like a built-in unary operator.
+ //
+ $$ = context->intermediate.addUnaryMath(op, $1.intermNode, @1, context->symbolTable);
+ if ($$ == 0) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>($1.intermNode)->getCompleteString();
+ std::string extraInfo = extraInfoStream.str();
+ context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
+ YYERROR;
+ }
+ } else {
+ $$ = context->intermediate.setAggregateOperator($1.intermAggregate, op, @1);
+ }
+ } else {
+ // This is a real function call
+
+ $$ = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, @1);
+ $$->setType(fnCandidate->getReturnType());
+
+ // this is how we know whether the given function is a builtIn function or a user defined function
+ // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
+ // if builtIn == true, it's definitely a builtIn function with EOpNull
+ if (!builtIn)
+ $$->getAsAggregate()->setUserDefined();
+ $$->getAsAggregate()->setName(fnCandidate->getMangledName());
+
+ TQualifier qual;
+ for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) {
+ qual = fnCandidate->getParam(i).type->getQualifier();
+ if (qual == EvqOut || qual == EvqInOut) {
+ if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) {
+ context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
+ context->recover();
+ }
+ }
+ }
+ }
+ $$->setType(fnCandidate->getReturnType());
+ } else {
+ // error message was put out by PaFindFunction()
+ // Put on a dummy node for error recovery
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), @1);
+ context->recover();
+ }
+ }
+ delete fnCall;
+ }
+ ;
+
+function_call_or_method
+ : function_call_generic {
+ $$ = $1;
+ }
+ | postfix_expression DOT function_call_generic {
+ context->error(@3, "methods are not supported", "");
+ context->recover();
+ $$ = $3;
+ }
+ ;
+
+function_call_generic
+ : function_call_header_with_parameters RIGHT_PAREN {
+ $$ = $1;
+ }
+ | function_call_header_no_parameters RIGHT_PAREN {
+ $$ = $1;
+ }
+ ;
+
+function_call_header_no_parameters
+ : function_call_header VOID_TYPE {
+ $$.function = $1;
+ $$.intermNode = 0;
+ }
+ | function_call_header {
+ $$.function = $1;
+ $$.intermNode = 0;
+ }
+ ;
+
+function_call_header_with_parameters
+ : function_call_header assignment_expression {
+ TParameter param = { 0, new TType($2->getType()) };
+ $1->addParameter(param);
+ $$.function = $1;
+ $$.intermNode = $2;
+ }
+ | function_call_header_with_parameters COMMA assignment_expression {
+ TParameter param = { 0, new TType($3->getType()) };
+ $1.function->addParameter(param);
+ $$.function = $1.function;
+ $$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, @2);
+ }
+ ;
+
+function_call_header
+ : function_identifier LEFT_PAREN {
+ $$ = $1;
+ }
+ ;
+
+// Grammar Note: Constructors look like functions, but are recognized as types.
+
+function_identifier
+ : type_specifier_nonarray {
+ //
+ // Constructor
+ //
+ TOperator op = EOpNull;
+ if ($1.userDef) {
+ op = EOpConstructStruct;
+ } else {
+ switch ($1.type) {
+ case EbtFloat:
+ if ($1.matrix) {
+ switch($1.size) {
+ case 2: op = EOpConstructMat2; break;
+ case 3: op = EOpConstructMat3; break;
+ case 4: op = EOpConstructMat4; break;
+ }
+ } else {
+ switch($1.size) {
+ case 1: op = EOpConstructFloat; break;
+ case 2: op = EOpConstructVec2; break;
+ case 3: op = EOpConstructVec3; break;
+ case 4: op = EOpConstructVec4; break;
+ }
+ }
+ break;
+ case EbtInt:
+ switch($1.size) {
+ case 1: op = EOpConstructInt; break;
+ case 2: op = EOpConstructIVec2; break;
+ case 3: op = EOpConstructIVec3; break;
+ case 4: op = EOpConstructIVec4; break;
+ }
+ break;
+ case EbtBool:
+ switch($1.size) {
+ case 1: op = EOpConstructBool; break;
+ case 2: op = EOpConstructBVec2; break;
+ case 3: op = EOpConstructBVec3; break;
+ case 4: op = EOpConstructBVec4; break;
+ }
+ break;
+ default: break;
+ }
+ if (op == EOpNull) {
+ context->error(@1, "cannot construct this type", getBasicString($1.type));
+ context->recover();
+ $1.type = EbtFloat;
+ op = EOpConstructFloat;
+ }
+ }
+ TString tempString;
+ TType type($1);
+ TFunction *function = new TFunction(&tempString, type, op);
+ $$ = function;
+ }
+ | IDENTIFIER {
+ if (context->reservedErrorCheck(@1, *$1.string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction($1.string, type);
+ $$ = function;
+ }
+ ;
+
+unary_expression
+ : postfix_expression {
+ $$ = $1;
+ }
+ | INC_OP unary_expression {
+ if (context->lValueErrorCheck(@1, "++", $2))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, @1, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError(@1, "++", $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ }
+ | DEC_OP unary_expression {
+ if (context->lValueErrorCheck(@1, "--", $2))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, @1, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError(@1, "--", $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ }
+ | unary_operator unary_expression {
+ if ($1.op != EOpNull) {
+ $$ = context->intermediate.addUnaryMath($1.op, $2, @1, context->symbolTable);
+ if ($$ == 0) {
+ const char* errorOp = "";
+ switch($1.op) {
+ case EOpNegative: errorOp = "-"; break;
+ case EOpLogicalNot: errorOp = "!"; break;
+ default: break;
+ }
+ context->unaryOpError(@1, errorOp, $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ } else
+ $$ = $2;
+ }
+ ;
+// Grammar Note: No traditional style type casts.
+
+unary_operator
+ : PLUS { $$.op = EOpNull; }
+ | DASH { $$.op = EOpNegative; }
+ | BANG { $$.op = EOpLogicalNot; }
+ ;
+// Grammar Note: No '*' or '&' unary ops. Pointers are not supported.
+
+multiplicative_expression
+ : unary_expression { $$ = $1; }
+ | multiplicative_expression STAR unary_expression {
+ $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "*", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | multiplicative_expression SLASH unary_expression {
+ $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "/", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression { $$ = $1; }
+ | additive_expression PLUS multiplicative_expression {
+ $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "+", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | additive_expression DASH multiplicative_expression {
+ $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "-", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+shift_expression
+ : additive_expression { $$ = $1; }
+ ;
+
+relational_expression
+ : shift_expression { $$ = $1; }
+ | relational_expression LEFT_ANGLE shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "<", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ | relational_expression RIGHT_ANGLE shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, ">", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ | relational_expression LE_OP shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "<=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ | relational_expression GE_OP shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, ">=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+equality_expression
+ : relational_expression { $$ = $1; }
+ | equality_expression EQ_OP relational_expression {
+ $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "==", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ | equality_expression NE_OP relational_expression {
+ $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "!=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+and_expression
+ : equality_expression { $$ = $1; }
+ ;
+
+exclusive_or_expression
+ : and_expression { $$ = $1; }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression { $$ = $1; }
+ ;
+
+logical_and_expression
+ : inclusive_or_expression { $$ = $1; }
+ | logical_and_expression AND_OP inclusive_or_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "&&", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+logical_xor_expression
+ : logical_and_expression { $$ = $1; }
+ | logical_xor_expression XOR_OP logical_and_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "^^", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+logical_or_expression
+ : logical_xor_expression { $$ = $1; }
+ | logical_or_expression OR_OP logical_xor_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, @2, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError(@2, "||", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2);
+ }
+ }
+ ;
+
+conditional_expression
+ : logical_or_expression { $$ = $1; }
+ | logical_or_expression QUESTION expression COLON assignment_expression {
+ if (context->boolErrorCheck(@2, $1))
+ context->recover();
+
+ $$ = context->intermediate.addSelection($1, $3, $5, @2);
+ if ($3->getType() != $5->getType())
+ $$ = 0;
+
+ if ($$ == 0) {
+ context->binaryOpError(@2, ":", $3->getCompleteString(), $5->getCompleteString());
+ context->recover();
+ $$ = $5;
+ }
+ }
+ ;
+
+assignment_expression
+ : conditional_expression { $$ = $1; }
+ | unary_expression assignment_operator assignment_expression {
+ if (context->lValueErrorCheck(@2, "assign", $1))
+ context->recover();
+ $$ = context->intermediate.addAssign($2.op, $1, $3, @2);
+ if ($$ == 0) {
+ context->assignError(@2, "assign", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+assignment_operator
+ : EQUAL { $$.op = EOpAssign; }
+ | MUL_ASSIGN { $$.op = EOpMulAssign; }
+ | DIV_ASSIGN { $$.op = EOpDivAssign; }
+ | ADD_ASSIGN { $$.op = EOpAddAssign; }
+ | SUB_ASSIGN { $$.op = EOpSubAssign; }
+ ;
+
+expression
+ : assignment_expression {
+ $$ = $1;
+ }
+ | expression COMMA assignment_expression {
+ $$ = context->intermediate.addComma($1, $3, @2);
+ if ($$ == 0) {
+ context->binaryOpError(@2, ",", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $3;
+ }
+ }
+ ;
+
+constant_expression
+ : conditional_expression {
+ if (context->constErrorCheck($1))
+ context->recover();
+ $$ = $1;
+ }
+ ;
+
+declaration
+ : function_prototype SEMICOLON {
+ TFunction &function = *($1.function);
+
+ TIntermAggregate *prototype = new TIntermAggregate;
+ prototype->setType(function.getReturnType());
+ prototype->setName(function.getName());
+
+ for (size_t i = 0; i < function.getParamCount(); i++)
+ {
+ const TParameter &param = function.getParam(i);
+ if (param.name != 0)
+ {
+ TVariable variable(param.name, *param.type);
+
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), @1), @1);
+ }
+ else
+ {
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, @1), @1);
+ }
+ }
+
+ prototype->setOp(EOpPrototype);
+ $$ = prototype;
+
+ context->symbolTable.pop();
+ }
+ | init_declarator_list SEMICOLON {
+ if ($1.intermAggregate)
+ $1.intermAggregate->setOp(EOpDeclaration);
+ $$ = $1.intermAggregate;
+ }
+ | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON {
+ if (($2 == EbpHigh) && (context->shaderType == SH_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) {
+ context->error(@1, "precision is not supported in fragment shader", "highp");
+ context->recover();
+ }
+ if (!context->symbolTable.setDefaultPrecision( $3, $2 )) {
+ context->error(@1, "illegal type argument for default precision qualifier", getBasicString($3.type));
+ context->recover();
+ }
+ $$ = 0;
+ }
+ ;
+
+function_prototype
+ : function_declarator RIGHT_PAREN {
+ //
+ // Multiple declarations of the same function are allowed.
+ //
+ // If this is a definition, the definition production code will check for redefinitions
+ // (we don't know at this point if it's a definition or not).
+ //
+ // Redeclarations are allowed. But, return types and parameter qualifiers must match.
+ //
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find($1->getMangledName()));
+ if (prevDec) {
+ if (prevDec->getReturnType() != $1->getReturnType()) {
+ context->error(@2, "overloaded functions must have the same return type", $1->getReturnType().getBasicString());
+ context->recover();
+ }
+ for (size_t i = 0; i < prevDec->getParamCount(); ++i) {
+ if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) {
+ context->error(@2, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString());
+ context->recover();
+ }
+ }
+ }
+
+ //
+ // Check for previously declared variables using the same name.
+ //
+ TSymbol *prevSym = context->symbolTable.find($1->getName());
+ if (prevSym)
+ {
+ if (!prevSym->isFunction())
+ {
+ context->error(@2, "redefinition", $1->getName().c_str(), "function");
+ context->recover();
+ }
+ }
+ else
+ {
+ // Insert the unmangled name to detect potential future redefinition as a variable.
+ context->symbolTable.getOuterLevel()->insert($1->getName(), *$1);
+ }
+
+ //
+ // If this is a redeclaration, it could also be a definition,
+ // in which case, we want to use the variable names from this one, and not the one that's
+ // being redeclared. So, pass back up this declaration, not the one in the symbol table.
+ //
+ $$.function = $1;
+
+ // We're at the inner scope level of the function's arguments and body statement.
+ // Add the function prototype to the surrounding scope instead.
+ context->symbolTable.getOuterLevel()->insert(*$$.function);
+ }
+ ;
+
+function_declarator
+ : function_header {
+ $$ = $1;
+ }
+ | function_header_with_parameters {
+ $$ = $1;
+ }
+ ;
+
+
+function_header_with_parameters
+ : function_header parameter_declaration {
+ // Add the parameter
+ $$ = $1;
+ if ($2.param.type->getBasicType() != EbtVoid)
+ $1->addParameter($2.param);
+ else
+ delete $2.param.type;
+ }
+ | function_header_with_parameters COMMA parameter_declaration {
+ //
+ // Only first parameter of one-parameter functions can be void
+ // The check for named parameters not being void is done in parameter_declarator
+ //
+ if ($3.param.type->getBasicType() == EbtVoid) {
+ //
+ // This parameter > first is void
+ //
+ context->error(@2, "cannot be an argument type except for '(void)'", "void");
+ context->recover();
+ delete $3.param.type;
+ } else {
+ // Add the parameter
+ $$ = $1;
+ $1->addParameter($3.param);
+ }
+ }
+ ;
+
+function_header
+ : fully_specified_type IDENTIFIER LEFT_PAREN {
+ if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) {
+ context->error(@2, "no qualifiers allowed for function return", getQualifierString($1.qualifier));
+ context->recover();
+ }
+ // make sure a sampler is not involved as well...
+ if (context->structQualifierErrorCheck(@2, $1))
+ context->recover();
+
+ // Add the function as a prototype after parsing it (we do not support recursion)
+ TFunction *function;
+ TType type($1);
+ function = new TFunction($2.string, type);
+ $$ = function;
+
+ context->symbolTable.push();
+ }
+ ;
+
+parameter_declarator
+ // Type + name
+ : type_specifier identifier {
+ if ($1.type == EbtVoid) {
+ context->error(@2, "illegal use of type 'void'", $2.string->c_str());
+ context->recover();
+ }
+ if (context->reservedErrorCheck(@2, *$2.string))
+ context->recover();
+ TParameter param = {$2.string, new TType($1)};
+ $$.param = param;
+ }
+ | type_specifier identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ // Check that we can make an array out of this type
+ if (context->arrayTypeErrorCheck(@3, $1))
+ context->recover();
+
+ if (context->reservedErrorCheck(@2, *$2.string))
+ context->recover();
+
+ int size;
+ if (context->arraySizeErrorCheck(@3, $4, size))
+ context->recover();
+ $1.setArray(true, size);
+
+ TType* type = new TType($1);
+ TParameter param = { $2.string, type };
+ $$.param = param;
+ }
+ ;
+
+parameter_declaration
+ //
+ // The only parameter qualifier a parameter can have are
+ // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST.
+ //
+
+ //
+ // Type + name
+ //
+ : type_qualifier parameter_qualifier parameter_declarator {
+ $$ = $3;
+ if (context->paramErrorCheck(@3, $1.qualifier, $2, $$.param.type))
+ context->recover();
+ }
+ | parameter_qualifier parameter_declarator {
+ $$ = $2;
+ if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type))
+ context->recover();
+ if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type))
+ context->recover();
+ }
+ //
+ // Only type
+ //
+ | type_qualifier parameter_qualifier parameter_type_specifier {
+ $$ = $3;
+ if (context->paramErrorCheck(@3, $1.qualifier, $2, $$.param.type))
+ context->recover();
+ }
+ | parameter_qualifier parameter_type_specifier {
+ $$ = $2;
+ if (context->parameterSamplerErrorCheck(@2, $1, *$2.param.type))
+ context->recover();
+ if (context->paramErrorCheck(@2, EvqTemporary, $1, $$.param.type))
+ context->recover();
+ }
+ ;
+
+parameter_qualifier
+ : /* empty */ {
+ $$ = EvqIn;
+ }
+ | IN_QUAL {
+ $$ = EvqIn;
+ }
+ | OUT_QUAL {
+ $$ = EvqOut;
+ }
+ | INOUT_QUAL {
+ $$ = EvqInOut;
+ }
+ ;
+
+parameter_type_specifier
+ : type_specifier {
+ TParameter param = { 0, new TType($1) };
+ $$.param = param;
+ }
+ ;
+
+init_declarator_list
+ : single_declaration {
+ $$ = $1;
+ }
+ | init_declarator_list COMMA identifier {
+ if ($1.type.type == EbtInvariant && !$3.symbol)
+ {
+ context->error(@3, "undeclared identifier declared as invariant", $3.string->c_str());
+ context->recover();
+ }
+
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$3.string, TType($1.type), @3);
+ $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, symbol, @3);
+
+ if (context->structQualifierErrorCheck(@3, $$.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck(@3, *$3.string, $$.type, false))
+ context->recover();
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck(@3, *$3.string, $$.type, variable))
+ context->recover();
+ if (symbol && variable)
+ symbol->setId(variable->getUniqueId());
+ }
+ | init_declarator_list COMMA identifier LEFT_BRACKET RIGHT_BRACKET {
+ if (context->structQualifierErrorCheck(@3, $1.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck(@3, *$3.string, $1.type, true))
+ context->recover();
+
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck(@4, $1.type) || context->arrayQualifierErrorCheck(@4, $1.type))
+ context->recover();
+ else {
+ $1.type.setArray(true);
+ TVariable* variable;
+ if (context->arrayErrorCheck(@4, *$3.string, $1.type, variable))
+ context->recover();
+ }
+ }
+ | init_declarator_list COMMA identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ if (context->structQualifierErrorCheck(@3, $1.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck(@3, *$3.string, $1.type, true))
+ context->recover();
+
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck(@4, $1.type) || context->arrayQualifierErrorCheck(@4, $1.type))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck(@4, $5, size))
+ context->recover();
+ $1.type.setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck(@4, *$3.string, $1.type, variable))
+ context->recover();
+ TType type = TType($1.type);
+ type.setArraySize(size);
+ $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *$3.string, type, @3), @3);
+ }
+ }
+ | init_declarator_list COMMA identifier EQUAL initializer {
+ if (context->structQualifierErrorCheck(@3, $1.type))
+ context->recover();
+
+ $$ = $1;
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer(@3, *$3.string, $1.type, $5, intermNode)) {
+ //
+ // build the intermediate representation
+ //
+ if (intermNode)
+ $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, intermNode, @4);
+ else
+ $$.intermAggregate = $1.intermAggregate;
+ } else {
+ context->recover();
+ $$.intermAggregate = 0;
+ }
+ }
+ ;
+
+single_declaration
+ : fully_specified_type {
+ $$.type = $1;
+ $$.intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType($1), @1), @1);
+ }
+ | fully_specified_type identifier {
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), @2);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2);
+
+ if (context->structQualifierErrorCheck(@2, $$.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck(@2, *$2.string, $$.type, false))
+ context->recover();
+
+ $$.type = $1;
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck(@2, *$2.string, $$.type, variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+ | fully_specified_type identifier LEFT_BRACKET RIGHT_BRACKET {
+ context->error(@2, "unsized array declarations not supported", $2.string->c_str());
+ context->recover();
+
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), @2);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2);
+ $$.type = $1;
+ }
+ | fully_specified_type identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ TType type = TType($1);
+ int size;
+ if (context->arraySizeErrorCheck(@2, $4, size))
+ context->recover();
+ type.setArraySize(size);
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, type, @2);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2);
+
+ if (context->structQualifierErrorCheck(@2, $1))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck(@2, *$2.string, $1, true))
+ context->recover();
+
+ $$.type = $1;
+
+ if (context->arrayTypeErrorCheck(@3, $1) || context->arrayQualifierErrorCheck(@3, $1))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck(@3, $4, size))
+ context->recover();
+
+ $1.setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck(@3, *$2.string, $1, variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+ }
+ | fully_specified_type identifier EQUAL initializer {
+ if (context->structQualifierErrorCheck(@2, $1))
+ context->recover();
+
+ $$.type = $1;
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode)) {
+ //
+ // Build intermediate representation
+ //
+ if(intermNode)
+ $$.intermAggregate = context->intermediate.makeAggregate(intermNode, @3);
+ else
+ $$.intermAggregate = 0;
+ } else {
+ context->recover();
+ $$.intermAggregate = 0;
+ }
+ }
+ | INVARIANT IDENTIFIER {
+ VERTEX_ONLY("invariant declaration", @1);
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ $$.type.setBasic(EbtInvariant, EvqInvariantVaryingOut, @2);
+ if (!$2.symbol)
+ {
+ context->error(@2, "undeclared identifier declared as invariant", $2.string->c_str());
+ context->recover();
+
+ $$.intermAggregate = 0;
+ }
+ else
+ {
+ TIntermSymbol *symbol = context->intermediate.addSymbol(0, *$2.string, TType($$.type), @2);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, @2);
+ }
+ }
+ ;
+
+fully_specified_type
+ : type_specifier {
+ $$ = $1;
+
+ if ($1.array) {
+ context->error(@1, "not supported", "first-class array");
+ context->recover();
+ $1.setArray(false);
+ }
+ }
+ | type_qualifier type_specifier {
+ if ($2.array) {
+ context->error(@2, "not supported", "first-class array");
+ context->recover();
+ $2.setArray(false);
+ }
+
+ if ($1.qualifier == EvqAttribute &&
+ ($2.type == EbtBool || $2.type == EbtInt)) {
+ context->error(@2, "cannot be bool or int", getQualifierString($1.qualifier));
+ context->recover();
+ }
+ if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) &&
+ ($2.type == EbtBool || $2.type == EbtInt)) {
+ context->error(@2, "cannot be bool or int", getQualifierString($1.qualifier));
+ context->recover();
+ }
+ $$ = $2;
+ $$.qualifier = $1.qualifier;
+ }
+ ;
+
+type_qualifier
+ : CONST_QUAL {
+ $$.setBasic(EbtVoid, EvqConst, @1);
+ }
+ | ATTRIBUTE {
+ VERTEX_ONLY("attribute", @1);
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "attribute"))
+ context->recover();
+ $$.setBasic(EbtVoid, EvqAttribute, @1);
+ }
+ | VARYING {
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ $$.setBasic(EbtVoid, EvqVaryingOut, @1);
+ else
+ $$.setBasic(EbtVoid, EvqVaryingIn, @1);
+ }
+ | INVARIANT VARYING {
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ $$.setBasic(EbtVoid, EvqInvariantVaryingOut, @1);
+ else
+ $$.setBasic(EbtVoid, EvqInvariantVaryingIn, @1);
+ }
+ | UNIFORM {
+ if (context->globalErrorCheck(@1, context->symbolTable.atGlobalLevel(), "uniform"))
+ context->recover();
+ $$.setBasic(EbtVoid, EvqUniform, @1);
+ }
+ ;
+
+type_specifier
+ : type_specifier_no_prec {
+ $$ = $1;
+
+ if ($$.precision == EbpUndefined) {
+ $$.precision = context->symbolTable.getDefaultPrecision($1.type);
+ if (context->precisionErrorCheck(@1, $$.precision, $1.type)) {
+ context->recover();
+ }
+ }
+ }
+ | precision_qualifier type_specifier_no_prec {
+ $$ = $2;
+ $$.precision = $1;
+ }
+ ;
+
+precision_qualifier
+ : HIGH_PRECISION {
+ $$ = EbpHigh;
+ }
+ | MEDIUM_PRECISION {
+ $$ = EbpMedium;
+ }
+ | LOW_PRECISION {
+ $$ = EbpLow;
+ }
+ ;
+
+type_specifier_no_prec
+ : type_specifier_nonarray {
+ $$ = $1;
+ }
+ | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck(@2, $1))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck(@2, $3, size))
+ context->recover();
+ $$.setArray(true, size);
+ }
+ }
+ ;
+
+type_specifier_nonarray
+ : VOID_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtVoid, qual, @1);
+ }
+ | FLOAT_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ }
+ | INT_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, @1);
+ }
+ | BOOL_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, @1);
+ }
+ | VEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setAggregate(2);
+ }
+ | VEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setAggregate(3);
+ }
+ | VEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setAggregate(4);
+ }
+ | BVEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, @1);
+ $$.setAggregate(2);
+ }
+ | BVEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, @1);
+ $$.setAggregate(3);
+ }
+ | BVEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, @1);
+ $$.setAggregate(4);
+ }
+ | IVEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, @1);
+ $$.setAggregate(2);
+ }
+ | IVEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, @1);
+ $$.setAggregate(3);
+ }
+ | IVEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, @1);
+ $$.setAggregate(4);
+ }
+ | MATRIX2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setAggregate(2, true);
+ }
+ | MATRIX3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setAggregate(3, true);
+ }
+ | MATRIX4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, @1);
+ $$.setAggregate(4, true);
+ }
+ | SAMPLER2D {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2D, qual, @1);
+ }
+ | SAMPLERCUBE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSamplerCube, qual, @1);
+ }
+ | SAMPLER_EXTERNAL_OES {
+ if (!context->supportsExtension("GL_OES_EGL_image_external")) {
+ context->error(@1, "unsupported type", "samplerExternalOES");
+ context->recover();
+ }
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSamplerExternalOES, qual, @1);
+ }
+ | SAMPLER2DRECT {
+ if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
+ context->error(@1, "unsupported type", "sampler2DRect");
+ context->recover();
+ }
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2DRect, qual, @1);
+ }
+ | struct_specifier {
+ $$ = $1;
+ $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ }
+ | TYPE_NAME {
+ //
+ // This is for user defined type names. The lexical phase looked up the
+ // type.
+ //
+ TType& structure = static_cast<TVariable*>($1.symbol)->getType();
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtStruct, qual, @1);
+ $$.userDef = &structure;
+ }
+ ;
+
+struct_specifier
+ : STRUCT identifier LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
+ if (context->reservedErrorCheck(@2, *$2.string))
+ context->recover();
+
+ TType* structure = new TType(new TStructure($2.string, $5));
+ TVariable* userTypeDef = new TVariable($2.string, *structure, true);
+ if (! context->symbolTable.insert(*userTypeDef)) {
+ context->error(@2, "redefinition", $2.string->c_str(), "struct");
+ context->recover();
+ }
+ $$.setBasic(EbtStruct, EvqTemporary, @1);
+ $$.userDef = structure;
+ context->exitStructDeclaration();
+ }
+ | STRUCT LEFT_BRACE { if (context->enterStructDeclaration(@2, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
+ TType* structure = new TType(new TStructure(NewPoolTString(""), $4));
+ $$.setBasic(EbtStruct, EvqTemporary, @1);
+ $$.userDef = structure;
+ context->exitStructDeclaration();
+ }
+ ;
+
+struct_declaration_list
+ : struct_declaration {
+ $$ = $1;
+ }
+ | struct_declaration_list struct_declaration {
+ $$ = $1;
+ for (size_t i = 0; i < $2->size(); ++i) {
+ TField* field = (*$2)[i];
+ for (size_t j = 0; j < $$->size(); ++j) {
+ if ((*$$)[j]->name() == field->name()) {
+ context->error(@2, "duplicate field name in structure:", "struct", field->name().c_str());
+ context->recover();
+ }
+ }
+ $$->push_back(field);
+ }
+ }
+ ;
+
+struct_declaration
+ : type_specifier struct_declarator_list SEMICOLON {
+ $$ = $2;
+
+ if (context->voidErrorCheck(@1, (*$2)[0]->name(), $1)) {
+ context->recover();
+ }
+ for (unsigned int i = 0; i < $$->size(); ++i) {
+ //
+ // Careful not to replace already known aspects of type, like array-ness
+ //
+ TType* type = (*$$)[i]->type();
+ type->setBasicType($1.type);
+ type->setNominalSize($1.size);
+ type->setMatrix($1.matrix);
+ type->setPrecision($1.precision);
+
+ // don't allow arrays of arrays
+ if (type->isArray()) {
+ if (context->arrayTypeErrorCheck(@1, $1))
+ context->recover();
+ }
+ if ($1.array)
+ type->setArraySize($1.arraySize);
+ if ($1.userDef)
+ type->setStruct($1.userDef->getStruct());
+
+ if (context->structNestingErrorCheck(@1, *(*$$)[i]))
+ context->recover();
+ }
+ }
+ ;
+
+struct_declarator_list
+ : struct_declarator {
+ $$ = NewPoolTFieldList();
+ $$->push_back($1);
+ }
+ | struct_declarator_list COMMA struct_declarator {
+ $$->push_back($3);
+ }
+ ;
+
+struct_declarator
+ : identifier {
+ if (context->reservedErrorCheck(@1, *$1.string))
+ context->recover();
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ $$ = new TField(type, $1.string);
+ }
+ | identifier LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ if (context->reservedErrorCheck(@1, *$1.string))
+ context->recover();
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ int size = 0;
+ if (context->arraySizeErrorCheck(@3, $3, size))
+ context->recover();
+ type->setArraySize(size);
+
+ $$ = new TField(type, $1.string);
+ }
+ ;
+
+initializer
+ : assignment_expression { $$ = $1; }
+ ;
+
+declaration_statement
+ : declaration { $$ = $1; }
+ ;
+
+statement
+ : compound_statement { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+// Grammar Note: No labeled statements; 'goto' is not supported.
+
+simple_statement
+ : declaration_statement { $$ = $1; }
+ | expression_statement { $$ = $1; }
+ | selection_statement { $$ = $1; }
+ | iteration_statement { $$ = $1; }
+ | jump_statement { $$ = $1; }
+ ;
+
+compound_statement
+ : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
+ | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE {
+ if ($3 != 0) {
+ $3->setOp(EOpSequence);
+ $3->setLine(@$);
+ }
+ $$ = $3;
+ }
+ ;
+
+statement_no_new_scope
+ : compound_statement_no_new_scope { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+statement_with_scope
+ : { context->symbolTable.push(); } compound_statement_no_new_scope { context->symbolTable.pop(); $$ = $2; }
+ | { context->symbolTable.push(); } simple_statement { context->symbolTable.pop(); $$ = $2; }
+ ;
+
+compound_statement_no_new_scope
+ // Statement that doesn't create a new scope, for selection_statement, iteration_statement
+ : LEFT_BRACE RIGHT_BRACE {
+ $$ = 0;
+ }
+ | LEFT_BRACE statement_list RIGHT_BRACE {
+ if ($2) {
+ $2->setOp(EOpSequence);
+ $2->setLine(@$);
+ }
+ $$ = $2;
+ }
+ ;
+
+statement_list
+ : statement {
+ $$ = context->intermediate.makeAggregate($1, @$);
+ }
+ | statement_list statement {
+ $$ = context->intermediate.growAggregate($1, $2, @$);
+ }
+ ;
+
+expression_statement
+ : SEMICOLON { $$ = 0; }
+ | expression SEMICOLON { $$ = static_cast<TIntermNode*>($1); }
+ ;
+
+selection_statement
+ : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
+ if (context->boolErrorCheck(@1, $3))
+ context->recover();
+ $$ = context->intermediate.addSelection($3, $5, @1);
+ }
+ ;
+
+selection_rest_statement
+ : statement_with_scope ELSE statement_with_scope {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ | statement_with_scope {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ ;
+
+// Grammar Note: No 'switch'. Switch statements not supported.
+
+condition
+ // In 1996 c++ draft, conditions can include single declarations
+ : expression {
+ $$ = $1;
+ if (context->boolErrorCheck($1->getLine(), $1))
+ context->recover();
+ }
+ | fully_specified_type identifier EQUAL initializer {
+ TIntermNode* intermNode;
+ if (context->structQualifierErrorCheck(@2, $1))
+ context->recover();
+ if (context->boolErrorCheck(@2, $1))
+ context->recover();
+
+ if (!context->executeInitializer(@2, *$2.string, $1, $4, intermNode))
+ $$ = $4;
+ else {
+ context->recover();
+ $$ = 0;
+ }
+ }
+ ;
+
+iteration_statement
+ : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1);
+ --context->loopNestingLevel;
+ }
+ | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
+ if (context->boolErrorCheck(@8, $6))
+ context->recover();
+
+ $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4);
+ --context->loopNestingLevel;
+ }
+ | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, @1);
+ --context->loopNestingLevel;
+ }
+ ;
+
+for_init_statement
+ : expression_statement {
+ $$ = $1;
+ }
+ | declaration_statement {
+ $$ = $1;
+ }
+ ;
+
+conditionopt
+ : condition {
+ $$ = $1;
+ }
+ | /* May be null */ {
+ $$ = 0;
+ }
+ ;
+
+for_rest_statement
+ : conditionopt SEMICOLON {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ | conditionopt SEMICOLON expression {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ ;
+
+jump_statement
+ : CONTINUE SEMICOLON {
+ if (context->loopNestingLevel <= 0) {
+ context->error(@1, "continue statement only allowed in loops", "");
+ context->recover();
+ }
+ $$ = context->intermediate.addBranch(EOpContinue, @1);
+ }
+ | BREAK SEMICOLON {
+ if (context->loopNestingLevel <= 0) {
+ context->error(@1, "break statement only allowed in loops", "");
+ context->recover();
+ }
+ $$ = context->intermediate.addBranch(EOpBreak, @1);
+ }
+ | RETURN SEMICOLON {
+ $$ = context->intermediate.addBranch(EOpReturn, @1);
+ if (context->currentFunctionType->getBasicType() != EbtVoid) {
+ context->error(@1, "non-void function must return a value", "return");
+ context->recover();
+ }
+ }
+ | RETURN expression SEMICOLON {
+ $$ = context->intermediate.addBranch(EOpReturn, $2, @1);
+ context->functionReturnsValue = true;
+ if (context->currentFunctionType->getBasicType() == EbtVoid) {
+ context->error(@1, "void function cannot return a value", "return");
+ context->recover();
+ } else if (*(context->currentFunctionType) != $2->getType()) {
+ context->error(@1, "function return is not matching type:", "return");
+ context->recover();
+ }
+ }
+ | DISCARD SEMICOLON {
+ FRAG_ONLY("discard", @1);
+ $$ = context->intermediate.addBranch(EOpKill, @1);
+ }
+ ;
+
+// Grammar Note: No 'goto'. Gotos are not supported.
+
+translation_unit
+ : external_declaration {
+ $$ = $1;
+ context->treeRoot = $$;
+ }
+ | translation_unit external_declaration {
+ $$ = context->intermediate.growAggregate($1, $2, @$);
+ context->treeRoot = $$;
+ }
+ ;
+
+external_declaration
+ : function_definition {
+ $$ = $1;
+ }
+ | declaration {
+ $$ = $1;
+ }
+ ;
+
+function_definition
+ : function_prototype {
+ TFunction* function = $1.function;
+
+ const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName());
+
+ if (builtIn)
+ {
+ context->error(@1, "built-in functions cannot be redefined", function->getName().c_str());
+ context->recover();
+ }
+
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName()));
+ //
+ // Note: 'prevDec' could be 'function' if this is the first time we've seen function
+ // as it would have just been put in the symbol table. Otherwise, we're looking up
+ // an earlier occurance.
+ //
+ if (prevDec->isDefined()) {
+ //
+ // Then this function already has a body.
+ //
+ context->error(@1, "function already has a body", function->getName().c_str());
+ context->recover();
+ }
+ prevDec->setDefined();
+
+ //
+ // Raise error message if main function takes any parameters or return anything other than void
+ //
+ if (function->getName() == "main") {
+ if (function->getParamCount() > 0) {
+ context->error(@1, "function cannot take any parameter(s)", function->getName().c_str());
+ context->recover();
+ }
+ if (function->getReturnType().getBasicType() != EbtVoid) {
+ context->error(@1, "", function->getReturnType().getBasicString(), "main function cannot return a value");
+ context->recover();
+ }
+ }
+
+ //
+ // Remember the return type for later checking for RETURN statements.
+ //
+ context->currentFunctionType = &(prevDec->getReturnType());
+ context->functionReturnsValue = false;
+
+ //
+ // Insert parameters into the symbol table.
+ // If the parameter has no name, it's not an error, just don't insert it
+ // (could be used for unused args).
+ //
+ // Also, accumulate the list of parameters into the HIL, so lower level code
+ // knows where to find parameters.
+ //
+ TIntermAggregate* paramNodes = new TIntermAggregate;
+ for (size_t i = 0; i < function->getParamCount(); i++) {
+ const TParameter& param = function->getParam(i);
+ if (param.name != 0) {
+ TVariable *variable = new TVariable(param.name, *param.type);
+ //
+ // Insert the parameters with name in the symbol table.
+ //
+ if (! context->symbolTable.insert(*variable)) {
+ context->error(@1, "redefinition", variable->getName().c_str());
+ context->recover();
+ delete variable;
+ }
+
+ //
+ // Add the parameter to the HIL
+ //
+ paramNodes = context->intermediate.growAggregate(
+ paramNodes,
+ context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(),
+ @1),
+ @1);
+ } else {
+ paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, @1), @1);
+ }
+ }
+ context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1);
+ $1.intermAggregate = paramNodes;
+ context->loopNestingLevel = 0;
+ }
+ compound_statement_no_new_scope {
+ //?? Check that all paths return a value if return type != void ?
+ // May be best done as post process phase on intermediate code
+ if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+ context->error(@1, "function does not return a value:", "", $1.function->getName().c_str());
+ context->recover();
+ }
+
+ $$ = context->intermediate.growAggregate($1.intermAggregate, $3, @$);
+ context->intermediate.setAggregateOperator($$, EOpFunction, @1);
+ $$->getAsAggregate()->setName($1.function->getMangledName().c_str());
+ $$->getAsAggregate()->setType($1.function->getReturnType());
+
+ // store the pragma information for debug and optimize and other vendor specific
+ // information. This information can be queried from the parse tree
+ $$->getAsAggregate()->setOptimize(context->pragma().optimize);
+ $$->getAsAggregate()->setDebug(context->pragma().debug);
+
+ context->symbolTable.pop();
+ }
+ ;
+
+%%
+
+void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason) {
+ context->error(*yylloc, reason, "");
+ context->recover();
+}
+
+int glslang_parse(TParseContext* context) {
+ return yyparse(context);
+}
diff --git a/src/compiler/glslang_lex.cpp b/src/compiler/glslang_lex.cpp
new file mode 100644
index 00000000..9f95521f
--- /dev/null
+++ b/src/compiler/glslang_lex.cpp
@@ -0,0 +1,2940 @@
+#line 17 "./glslang.l"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+
+
+
+#line 25 "./glslang_lex.cpp"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ yy_size_t yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void yypop_buffer_state (yyscan_t yyscanner );
+
+static void yyensure_buffer_stack (yyscan_t yyscanner );
+static void yy_load_buffer_state (yyscan_t yyscanner );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (yy_size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 147
+#define YY_END_OF_BUFFER 148
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[443] =
+ { 0,
+ 0, 0, 148, 146, 145, 145, 132, 138, 143, 127,
+ 128, 136, 135, 124, 133, 131, 137, 96, 96, 125,
+ 121, 139, 126, 140, 144, 93, 129, 130, 142, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 122,
+ 141, 123, 134, 118, 104, 123, 112, 107, 102, 110,
+ 100, 111, 101, 99, 103, 98, 95, 96, 0, 0,
+ 130, 122, 129, 119, 115, 117, 116, 120, 93, 108,
+ 114, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 12, 93, 93, 93, 93, 93, 93, 93, 93,
+
+ 93, 93, 93, 93, 93, 15, 17, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 109, 113, 0, 98, 0, 0,
+ 97, 94, 105, 106, 45, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 13, 93, 93, 93, 93, 93, 93,
+ 93, 93, 21, 93, 93, 93, 93, 93, 93, 93,
+ 93, 18, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+
+ 93, 93, 93, 93, 93, 0, 99, 0, 98, 93,
+ 23, 93, 93, 90, 93, 93, 93, 93, 93, 93,
+ 93, 16, 48, 93, 93, 93, 64, 93, 93, 53,
+ 68, 93, 93, 93, 93, 93, 93, 93, 93, 65,
+ 4, 28, 29, 30, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 51, 24, 93, 93, 93, 93, 93, 93, 31, 32,
+ 33, 22, 93, 93, 93, 10, 37, 38, 39, 46,
+ 7, 93, 93, 93, 93, 77, 78, 79, 93, 25,
+ 69, 20, 80, 81, 82, 2, 74, 75, 76, 93,
+
+ 19, 72, 93, 93, 34, 35, 36, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 66, 93, 93, 93,
+ 93, 93, 93, 93, 93, 47, 93, 92, 93, 93,
+ 14, 93, 93, 93, 93, 67, 61, 56, 93, 93,
+ 93, 93, 93, 73, 52, 93, 59, 27, 93, 89,
+ 60, 44, 71, 54, 93, 93, 93, 93, 93, 93,
+ 93, 93, 55, 26, 93, 93, 93, 3, 93, 93,
+ 93, 93, 93, 49, 8, 93, 9, 93, 93, 11,
+ 62, 93, 93, 93, 57, 93, 93, 93, 93, 93,
+ 93, 50, 70, 58, 6, 63, 1, 91, 5, 83,
+
+ 40, 84, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 41, 93, 93, 93, 93, 93,
+ 93, 93, 43, 93, 87, 93, 93, 93, 93, 93,
+ 85, 93, 86, 93, 93, 93, 93, 93, 93, 42,
+ 88, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 1, 1, 1, 5, 6, 1, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 20, 20, 21, 21, 22, 23, 24,
+ 25, 26, 27, 1, 28, 28, 29, 30, 31, 28,
+ 32, 32, 32, 32, 32, 32, 32, 32, 33, 32,
+ 32, 34, 35, 32, 32, 32, 32, 36, 32, 32,
+ 37, 1, 38, 39, 32, 1, 40, 41, 42, 43,
+
+ 44, 45, 46, 47, 48, 32, 49, 50, 51, 52,
+ 53, 54, 32, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64, 65, 66, 67, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[68] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[445] =
+ { 0,
+ 0, 0, 587, 588, 588, 588, 561, 43, 64, 588,
+ 588, 560, 61, 588, 60, 58, 559, 77, 86, 557,
+ 588, 104, 557, 55, 588, 0, 588, 588, 75, 26,
+ 57, 82, 83, 73, 93, 528, 97, 95, 527, 44,
+ 71, 521, 104, 534, 110, 116, 35, 111, 530, 588,
+ 114, 588, 588, 588, 588, 588, 588, 588, 588, 588,
+ 588, 588, 588, 165, 588, 172, 202, 211, 233, 0,
+ 588, 588, 588, 551, 588, 588, 588, 550, 0, 588,
+ 588, 523, 516, 519, 527, 526, 513, 528, 515, 521,
+ 509, 506, 519, 506, 503, 503, 509, 497, 108, 502,
+
+ 512, 498, 504, 507, 508, 0, 145, 507, 113, 493,
+ 506, 497, 499, 489, 503, 500, 502, 485, 490, 487,
+ 476, 157, 484, 489, 485, 487, 476, 479, 118, 484,
+ 476, 488, 70, 481, 588, 588, 246, 253, 270, 219,
+ 283, 0, 588, 588, 0, 473, 477, 486, 483, 467,
+ 467, 119, 482, 479, 479, 477, 474, 466, 472, 459,
+ 470, 456, 472, 0, 469, 457, 464, 461, 465, 458,
+ 447, 446, 459, 462, 459, 454, 445, 188, 450, 453,
+ 444, 441, 445, 451, 442, 433, 436, 434, 444, 430,
+ 428, 441, 427, 429, 426, 437, 436, 124, 431, 426,
+
+ 415, 258, 433, 435, 424, 290, 297, 304, 311, 425,
+ 0, 423, 275, 0, 415, 413, 421, 410, 427, 416,
+ 316, 0, 0, 410, 420, 420, 0, 405, 319, 0,
+ 0, 407, 322, 408, 402, 401, 402, 401, 325, 0,
+ 0, 0, 0, 0, 397, 398, 403, 394, 407, 402,
+ 401, 393, 397, 389, 392, 396, 401, 387, 399, 390,
+ 0, 0, 396, 385, 385, 390, 389, 386, 0, 0,
+ 0, 0, 376, 388, 390, 0, 0, 0, 0, 0,
+ 0, 378, 379, 373, 383, 0, 0, 0, 374, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 381,
+
+ 0, 0, 379, 375, 0, 0, 0, 371, 367, 372,
+ 362, 375, 361, 374, 363, 370, 0, 368, 370, 354,
+ 356, 362, 368, 363, 351, 0, 353, 0, 352, 355,
+ 0, 344, 343, 343, 356, 0, 358, 0, 357, 356,
+ 341, 354, 341, 0, 0, 344, 0, 0, 336, 0,
+ 0, 0, 0, 0, 333, 344, 337, 343, 340, 335,
+ 327, 339, 0, 0, 332, 339, 328, 0, 337, 334,
+ 324, 329, 332, 0, 0, 332, 0, 330, 329, 0,
+ 0, 328, 314, 326, 0, 317, 338, 337, 336, 307,
+ 303, 0, 0, 0, 0, 0, 0, 0, 0, 328,
+
+ 166, 325, 316, 299, 308, 310, 306, 308, 307, 306,
+ 309, 306, 256, 253, 0, 228, 238, 222, 235, 203,
+ 207, 204, 212, 191, 0, 201, 165, 167, 153, 161,
+ 0, 170, 0, 175, 151, 141, 100, 114, 59, 0,
+ 0, 588, 359, 113
+ } ;
+
+static yyconst flex_int16_t yy_def[445] =
+ { 0,
+ 442, 1, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 443, 442, 442, 442, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 444,
+ 442, 442, 442, 442, 442, 442, 442, 442, 443, 442,
+ 442, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 442, 442, 442, 442, 442, 442,
+ 442, 444, 442, 442, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+
+ 443, 443, 443, 443, 443, 442, 442, 442, 442, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
+ 443, 0, 442, 442
+ } ;
+
+static yyconst flex_int16_t yy_nxt[656] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 19, 19, 19, 19,
+ 19, 20, 21, 22, 23, 24, 25, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 26, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 26, 26, 26, 50, 51, 52, 53, 55, 56, 57,
+ 60, 62, 64, 64, 64, 64, 64, 64, 64, 77,
+ 78, 82, 83, 110, 63, 61, 129, 111, 58, 66,
+ 130, 67, 67, 67, 67, 67, 67, 68, 66, 80,
+
+ 68, 68, 68, 68, 68, 68, 68, 69, 72, 84,
+ 112, 85, 70, 81, 142, 86, 69, 203, 441, 204,
+ 69, 87, 94, 113, 95, 73, 90, 74, 75, 69,
+ 91, 88, 97, 96, 89, 92, 103, 70, 135, 106,
+ 98, 93, 99, 115, 104, 100, 107, 162, 440, 119,
+ 131, 101, 439, 108, 132, 105, 120, 121, 116, 125,
+ 163, 117, 126, 133, 176, 198, 122, 123, 264, 124,
+ 127, 438, 177, 199, 216, 217, 265, 128, 136, 64,
+ 64, 64, 64, 64, 64, 64, 138, 138, 138, 138,
+ 138, 138, 138, 437, 170, 137, 190, 171, 172, 406,
+
+ 407, 173, 139, 174, 242, 243, 244, 436, 137, 435,
+ 434, 191, 433, 432, 66, 139, 67, 67, 67, 67,
+ 67, 67, 68, 66, 431, 68, 68, 68, 68, 68,
+ 68, 68, 69, 141, 141, 141, 141, 141, 141, 141,
+ 430, 69, 140, 429, 140, 69, 428, 141, 141, 141,
+ 141, 141, 141, 141, 69, 206, 427, 206, 426, 425,
+ 207, 207, 207, 207, 207, 207, 207, 138, 138, 138,
+ 138, 138, 138, 138, 269, 270, 271, 424, 423, 208,
+ 422, 208, 421, 139, 209, 209, 209, 209, 209, 209,
+ 209, 277, 278, 279, 420, 419, 139, 141, 141, 141,
+
+ 141, 141, 141, 141, 207, 207, 207, 207, 207, 207,
+ 207, 207, 207, 207, 207, 207, 207, 207, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 286, 287, 288, 293, 294, 295, 297, 298,
+ 299, 305, 306, 307, 387, 388, 389, 418, 417, 416,
+ 415, 414, 413, 412, 411, 410, 409, 390, 408, 391,
+ 79, 79, 405, 404, 403, 402, 401, 400, 399, 398,
+ 397, 396, 395, 394, 393, 392, 386, 385, 384, 383,
+ 382, 381, 380, 379, 378, 377, 376, 375, 374, 373,
+ 372, 371, 370, 369, 368, 367, 366, 365, 364, 363,
+
+ 362, 361, 360, 359, 358, 357, 356, 355, 354, 353,
+ 352, 351, 350, 349, 348, 347, 346, 345, 344, 343,
+ 342, 341, 340, 339, 338, 337, 336, 335, 334, 333,
+ 332, 331, 330, 329, 328, 327, 326, 325, 324, 323,
+ 322, 321, 320, 319, 318, 317, 316, 315, 314, 313,
+ 312, 311, 310, 309, 308, 304, 303, 302, 301, 300,
+ 296, 292, 291, 290, 289, 285, 284, 283, 282, 281,
+ 280, 276, 275, 274, 273, 272, 268, 267, 266, 263,
+ 262, 261, 260, 259, 258, 257, 256, 255, 254, 253,
+ 252, 251, 250, 249, 248, 247, 246, 245, 241, 240,
+
+ 239, 238, 237, 236, 235, 234, 233, 232, 231, 230,
+ 229, 228, 227, 226, 225, 224, 223, 222, 221, 220,
+ 219, 218, 215, 214, 213, 212, 211, 210, 205, 202,
+ 201, 200, 197, 196, 195, 194, 193, 192, 189, 188,
+ 187, 186, 185, 184, 183, 182, 181, 180, 179, 178,
+ 175, 169, 168, 167, 166, 165, 164, 161, 160, 159,
+ 158, 157, 156, 155, 154, 153, 152, 151, 150, 149,
+ 148, 147, 146, 145, 144, 143, 134, 118, 114, 109,
+ 102, 76, 71, 65, 59, 54, 442, 3, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442
+ } ;
+
+static yyconst flex_int16_t yy_chk[656] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 8, 8, 9,
+ 13, 15, 16, 16, 16, 16, 16, 16, 16, 24,
+ 24, 30, 30, 40, 15, 13, 47, 40, 9, 18,
+ 47, 18, 18, 18, 18, 18, 18, 18, 19, 29,
+
+ 19, 19, 19, 19, 19, 19, 19, 18, 22, 31,
+ 41, 31, 18, 29, 444, 31, 19, 133, 439, 133,
+ 18, 32, 34, 41, 34, 22, 33, 22, 22, 19,
+ 33, 32, 35, 34, 32, 33, 37, 18, 51, 38,
+ 35, 33, 35, 43, 37, 35, 38, 99, 438, 45,
+ 48, 35, 437, 38, 48, 37, 45, 45, 43, 46,
+ 99, 43, 46, 48, 109, 129, 45, 45, 198, 45,
+ 46, 436, 109, 129, 152, 152, 198, 46, 51, 64,
+ 64, 64, 64, 64, 64, 64, 66, 66, 66, 66,
+ 66, 66, 66, 435, 107, 64, 122, 107, 107, 401,
+
+ 401, 107, 66, 107, 178, 178, 178, 434, 64, 432,
+ 430, 122, 429, 428, 67, 66, 67, 67, 67, 67,
+ 67, 67, 67, 68, 427, 68, 68, 68, 68, 68,
+ 68, 68, 67, 140, 140, 140, 140, 140, 140, 140,
+ 426, 68, 69, 424, 69, 67, 423, 69, 69, 69,
+ 69, 69, 69, 69, 68, 137, 422, 137, 421, 420,
+ 137, 137, 137, 137, 137, 137, 137, 138, 138, 138,
+ 138, 138, 138, 138, 202, 202, 202, 419, 418, 139,
+ 417, 139, 416, 138, 139, 139, 139, 139, 139, 139,
+ 139, 213, 213, 213, 414, 413, 138, 141, 141, 141,
+
+ 141, 141, 141, 141, 206, 206, 206, 206, 206, 206,
+ 206, 207, 207, 207, 207, 207, 207, 207, 208, 208,
+ 208, 208, 208, 208, 208, 209, 209, 209, 209, 209,
+ 209, 209, 221, 221, 221, 229, 229, 229, 233, 233,
+ 233, 239, 239, 239, 372, 372, 372, 412, 411, 410,
+ 409, 408, 407, 406, 405, 404, 403, 372, 402, 372,
+ 443, 443, 400, 391, 390, 389, 388, 387, 386, 384,
+ 383, 382, 379, 378, 376, 373, 371, 370, 369, 367,
+ 366, 365, 362, 361, 360, 359, 358, 357, 356, 355,
+ 349, 346, 343, 342, 341, 340, 339, 337, 335, 334,
+
+ 333, 332, 330, 329, 327, 325, 324, 323, 322, 321,
+ 320, 319, 318, 316, 315, 314, 313, 312, 311, 310,
+ 309, 308, 304, 303, 300, 289, 285, 284, 283, 282,
+ 275, 274, 273, 268, 267, 266, 265, 264, 263, 260,
+ 259, 258, 257, 256, 255, 254, 253, 252, 251, 250,
+ 249, 248, 247, 246, 245, 238, 237, 236, 235, 234,
+ 232, 228, 226, 225, 224, 220, 219, 218, 217, 216,
+ 215, 212, 210, 205, 204, 203, 201, 200, 199, 197,
+ 196, 195, 194, 193, 192, 191, 190, 189, 188, 187,
+ 186, 185, 184, 183, 182, 181, 180, 179, 177, 176,
+
+ 175, 174, 173, 172, 171, 170, 169, 168, 167, 166,
+ 165, 163, 162, 161, 160, 159, 158, 157, 156, 155,
+ 154, 153, 151, 150, 149, 148, 147, 146, 134, 132,
+ 131, 130, 128, 127, 126, 125, 124, 123, 121, 120,
+ 119, 118, 117, 116, 115, 114, 113, 112, 111, 110,
+ 108, 105, 104, 103, 102, 101, 100, 98, 97, 96,
+ 95, 94, 93, 92, 91, 90, 89, 88, 87, 86,
+ 85, 84, 83, 82, 78, 74, 49, 44, 42, 39,
+ 36, 23, 20, 17, 12, 7, 3, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[148] =
+ { 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/*
+//
+// 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.
+//
+
+This file contains the Lex specification for GLSL ES.
+Based on ANSI C grammar, Lex specification:
+http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
+*/
+
+#include "compiler/glslang.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/preprocessor/Token.h"
+#include "compiler/util.h"
+#include "glslang_tab.h"
+
+/* windows only pragma */
+#ifdef _MSC_VER
+#pragma warning(disable : 4102)
+#endif
+
+#define YY_USER_ACTION \
+ yylloc->first_file = yylloc->last_file = yycolumn; \
+ yylloc->first_line = yylloc->last_line = yylineno;
+
+#define YY_INPUT(buf, result, max_size) \
+ result = string_input(buf, max_size, yyscanner);
+
+static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner);
+static int check_type(yyscan_t yyscanner);
+static int reserved_word(yyscan_t yyscanner);
+
+#define INITIAL 0
+
+#define YY_EXTRA_TYPE TParseContext*
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ yy_size_t yy_n_chars;
+ yy_size_t yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ YYSTYPE * yylval_r;
+
+ YYLTYPE * yylloc_r;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+ /* This must go here because YYSTYPE and YYLTYPE are included
+ * from bison output in section 1.*/
+ # define yylval yyg->yylval_r
+
+ # define yylloc yyg->yylloc_r
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (yyscan_t yyscanner );
+
+int yyget_debug (yyscan_t yyscanner );
+
+void yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *yyget_in (yyscan_t yyscanner );
+
+void yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *yyget_out (yyscan_t yyscanner );
+
+void yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t yyget_leng (yyscan_t yyscanner );
+
+char *yyget_text (yyscan_t yyscanner );
+
+int yyget_lineno (yyscan_t yyscanner );
+
+void yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * yyget_lval (yyscan_t yyscanner );
+
+void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+ YYLTYPE *yyget_lloc (yyscan_t yyscanner );
+
+ void yyset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (yyscan_t yyscanner );
+#else
+extern int yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ yy_size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex \
+ (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int yylex \
+ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yylval = yylval_param;
+
+ yylloc = yylloc_param;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ yy_load_buffer_state(yyscanner );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 443 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 442 );
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ yy_size_t yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{ return INVARIANT; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{ return HIGH_PRECISION; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+{ return MEDIUM_PRECISION; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{ return LOW_PRECISION; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{ return PRECISION; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{ return ATTRIBUTE; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{ return CONST_QUAL; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{ return UNIFORM; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{ return VARYING; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{ return BREAK; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+{ return CONTINUE; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ return DO; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{ return FOR; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ return WHILE; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ return IF; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ return ELSE; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ return IN_QUAL; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+{ return OUT_QUAL; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{ return INOUT_QUAL; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{ return FLOAT_TYPE; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{ return INT_TYPE; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{ return VOID_TYPE; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+{ return BOOL_TYPE; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{ yylval->lex.b = true; return BOOLCONSTANT; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+{ yylval->lex.b = false; return BOOLCONSTANT; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{ return DISCARD; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{ return RETURN; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+{ return MATRIX2; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+{ return MATRIX3; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+{ return MATRIX4; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+{ return VEC2; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{ return VEC3; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+{ return VEC4; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+{ return IVEC2; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+{ return IVEC3; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+{ return IVEC4; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+{ return BVEC2; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+{ return BVEC3; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+{ return BVEC4; }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+{ return SAMPLER2D; }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+{ return SAMPLERCUBE; }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+{ return SAMPLER_EXTERNAL_OES; }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+{ return SAMPLER2DRECT; }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+{ return STRUCT; }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+{
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+}
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+{ yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+{ yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+{ yylval->lex.i = static_cast<int>(strtol(yytext, 0, 0)); return INTCONSTANT; }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return FLOATCONSTANT; }
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+{ return ADD_ASSIGN; }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+{ return SUB_ASSIGN; }
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+{ return MUL_ASSIGN; }
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+{ return DIV_ASSIGN; }
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+{ return MOD_ASSIGN; }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+{ return LEFT_ASSIGN; }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+{ return RIGHT_ASSIGN; }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+{ return AND_ASSIGN; }
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+{ return XOR_ASSIGN; }
+ YY_BREAK
+case 109:
+YY_RULE_SETUP
+{ return OR_ASSIGN; }
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+{ return INC_OP; }
+ YY_BREAK
+case 111:
+YY_RULE_SETUP
+{ return DEC_OP; }
+ YY_BREAK
+case 112:
+YY_RULE_SETUP
+{ return AND_OP; }
+ YY_BREAK
+case 113:
+YY_RULE_SETUP
+{ return OR_OP; }
+ YY_BREAK
+case 114:
+YY_RULE_SETUP
+{ return XOR_OP; }
+ YY_BREAK
+case 115:
+YY_RULE_SETUP
+{ return LE_OP; }
+ YY_BREAK
+case 116:
+YY_RULE_SETUP
+{ return GE_OP; }
+ YY_BREAK
+case 117:
+YY_RULE_SETUP
+{ return EQ_OP; }
+ YY_BREAK
+case 118:
+YY_RULE_SETUP
+{ return NE_OP; }
+ YY_BREAK
+case 119:
+YY_RULE_SETUP
+{ return LEFT_OP; }
+ YY_BREAK
+case 120:
+YY_RULE_SETUP
+{ return RIGHT_OP; }
+ YY_BREAK
+case 121:
+YY_RULE_SETUP
+{ return SEMICOLON; }
+ YY_BREAK
+case 122:
+YY_RULE_SETUP
+{ return LEFT_BRACE; }
+ YY_BREAK
+case 123:
+YY_RULE_SETUP
+{ return RIGHT_BRACE; }
+ YY_BREAK
+case 124:
+YY_RULE_SETUP
+{ return COMMA; }
+ YY_BREAK
+case 125:
+YY_RULE_SETUP
+{ return COLON; }
+ YY_BREAK
+case 126:
+YY_RULE_SETUP
+{ return EQUAL; }
+ YY_BREAK
+case 127:
+YY_RULE_SETUP
+{ return LEFT_PAREN; }
+ YY_BREAK
+case 128:
+YY_RULE_SETUP
+{ return RIGHT_PAREN; }
+ YY_BREAK
+case 129:
+YY_RULE_SETUP
+{ return LEFT_BRACKET; }
+ YY_BREAK
+case 130:
+YY_RULE_SETUP
+{ return RIGHT_BRACKET; }
+ YY_BREAK
+case 131:
+YY_RULE_SETUP
+{ return DOT; }
+ YY_BREAK
+case 132:
+YY_RULE_SETUP
+{ return BANG; }
+ YY_BREAK
+case 133:
+YY_RULE_SETUP
+{ return DASH; }
+ YY_BREAK
+case 134:
+YY_RULE_SETUP
+{ return TILDE; }
+ YY_BREAK
+case 135:
+YY_RULE_SETUP
+{ return PLUS; }
+ YY_BREAK
+case 136:
+YY_RULE_SETUP
+{ return STAR; }
+ YY_BREAK
+case 137:
+YY_RULE_SETUP
+{ return SLASH; }
+ YY_BREAK
+case 138:
+YY_RULE_SETUP
+{ return PERCENT; }
+ YY_BREAK
+case 139:
+YY_RULE_SETUP
+{ return LEFT_ANGLE; }
+ YY_BREAK
+case 140:
+YY_RULE_SETUP
+{ return RIGHT_ANGLE; }
+ YY_BREAK
+case 141:
+YY_RULE_SETUP
+{ return VERTICAL_BAR; }
+ YY_BREAK
+case 142:
+YY_RULE_SETUP
+{ return CARET; }
+ YY_BREAK
+case 143:
+YY_RULE_SETUP
+{ return AMPERSAND; }
+ YY_BREAK
+case 144:
+YY_RULE_SETUP
+{ return QUESTION; }
+ YY_BREAK
+case 145:
+/* rule 145 can match eol */
+YY_RULE_SETUP
+{ }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+{ yyterminate(); }
+ YY_BREAK
+case 146:
+YY_RULE_SETUP
+{ assert(false); return 0; }
+ YY_BREAK
+case 147:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = yyg->yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 443 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ register int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ register char *yy_cp = yyg->yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 443 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 442);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ if ( c == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+ yyfree((void *) b ,yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n, i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner);
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "yyset_column called with no buffer" , yyscanner);
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * yyget_lval (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylval;
+}
+
+void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylval = yylval_param;
+}
+
+YYLTYPE *yyget_lloc (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylloc;
+}
+
+void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylloc = yylloc_param;
+}
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+
+int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner) {
+ pp::Token token;
+ yyget_extra(yyscanner)->preprocessor.lex(&token);
+ yy_size_t len = token.type == pp::Token::LAST ? 0 : token.text.size();
+ if (len < max_size)
+ memcpy(buf, token.text.c_str(), len);
+ yyset_column(token.location.file,yyscanner);
+ yyset_lineno(token.location.line,yyscanner);
+
+ if (len >= max_size)
+ YY_FATAL_ERROR("Input buffer overflow");
+ else if (len > 0)
+ buf[len++] = ' ';
+ return len;
+}
+
+int check_type(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ int token = IDENTIFIER;
+ TSymbol* symbol = yyextra->symbolTable.find(yytext);
+ if (symbol && symbol->isVariable()) {
+ TVariable* variable = static_cast<TVariable*>(symbol);
+ if (variable->isUserType())
+ token = TYPE_NAME;
+ }
+ yylval->lex.symbol = symbol;
+ return token;
+}
+
+int reserved_word(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ yyextra->error(*yylloc, "Illegal use of reserved word", yytext, "");
+ yyextra->recover();
+ return 0;
+}
+
+int glslang_initialize(TParseContext* context) {
+ yyscan_t scanner = NULL;
+ if (yylex_init_extra(context,&scanner))
+ return 1;
+
+ context->scanner = scanner;
+ return 0;
+}
+
+int glslang_finalize(TParseContext* context) {
+ yyscan_t scanner = context->scanner;
+ if (scanner == NULL) return 0;
+
+ context->scanner = NULL;
+ yylex_destroy(scanner);
+
+ return 0;
+}
+
+int glslang_scan(size_t count, const char* const string[], const int length[],
+ TParseContext* context) {
+ yyrestart(NULL,context->scanner);
+ yyset_column(0,context->scanner);
+ yyset_lineno(1,context->scanner);
+
+ // Initialize preprocessor.
+ if (!context->preprocessor.init(count, string, length))
+ return 1;
+
+ // Define extension macros.
+ const TExtensionBehavior& extBehavior = context->extensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
+ iter != extBehavior.end(); ++iter) {
+ context->preprocessor.predefineMacro(iter->first.c_str(), 1);
+ }
+ if (context->fragmentPrecisionHigh)
+ context->preprocessor.predefineMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ return 0;
+}
+
diff --git a/src/compiler/glslang_tab.cpp b/src/compiler/glslang_tab.cpp
new file mode 100644
index 00000000..7afd4ca8
--- /dev/null
+++ b/src/compiler/glslang_tab.cpp
@@ -0,0 +1,4882 @@
+/* A Bison parser, made by GNU Bison 2.7. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.7"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations. */
+
+
+//
+// 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.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+// Ignore errors in auto-generated code.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4189)
+#pragma warning(disable: 4505)
+#pragma warning(disable: 4701)
+#endif
+
+#include "compiler/SymbolTable.h"
+#include "compiler/ParseHelper.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYENABLE_NLS 0
+
+#define YYLEX_PARAM context->scanner
+
+
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "glslang_tab.h". */
+#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED
+# define YY_YY_GLSLANG_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+/* "%code requires" blocks. */
+
+
+#define YYLTYPE TSourceLoc
+#define YYLTYPE_IS_DECLARED 1
+
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INVARIANT = 258,
+ HIGH_PRECISION = 259,
+ MEDIUM_PRECISION = 260,
+ LOW_PRECISION = 261,
+ PRECISION = 262,
+ ATTRIBUTE = 263,
+ CONST_QUAL = 264,
+ BOOL_TYPE = 265,
+ FLOAT_TYPE = 266,
+ INT_TYPE = 267,
+ BREAK = 268,
+ CONTINUE = 269,
+ DO = 270,
+ ELSE = 271,
+ FOR = 272,
+ IF = 273,
+ DISCARD = 274,
+ RETURN = 275,
+ BVEC2 = 276,
+ BVEC3 = 277,
+ BVEC4 = 278,
+ IVEC2 = 279,
+ IVEC3 = 280,
+ IVEC4 = 281,
+ VEC2 = 282,
+ VEC3 = 283,
+ VEC4 = 284,
+ MATRIX2 = 285,
+ MATRIX3 = 286,
+ MATRIX4 = 287,
+ IN_QUAL = 288,
+ OUT_QUAL = 289,
+ INOUT_QUAL = 290,
+ UNIFORM = 291,
+ VARYING = 292,
+ STRUCT = 293,
+ VOID_TYPE = 294,
+ WHILE = 295,
+ SAMPLER2D = 296,
+ SAMPLERCUBE = 297,
+ SAMPLER_EXTERNAL_OES = 298,
+ SAMPLER2DRECT = 299,
+ IDENTIFIER = 300,
+ TYPE_NAME = 301,
+ FLOATCONSTANT = 302,
+ INTCONSTANT = 303,
+ BOOLCONSTANT = 304,
+ LEFT_OP = 305,
+ RIGHT_OP = 306,
+ INC_OP = 307,
+ DEC_OP = 308,
+ LE_OP = 309,
+ GE_OP = 310,
+ EQ_OP = 311,
+ NE_OP = 312,
+ AND_OP = 313,
+ OR_OP = 314,
+ XOR_OP = 315,
+ MUL_ASSIGN = 316,
+ DIV_ASSIGN = 317,
+ ADD_ASSIGN = 318,
+ MOD_ASSIGN = 319,
+ LEFT_ASSIGN = 320,
+ RIGHT_ASSIGN = 321,
+ AND_ASSIGN = 322,
+ XOR_ASSIGN = 323,
+ OR_ASSIGN = 324,
+ SUB_ASSIGN = 325,
+ LEFT_PAREN = 326,
+ RIGHT_PAREN = 327,
+ LEFT_BRACKET = 328,
+ RIGHT_BRACKET = 329,
+ LEFT_BRACE = 330,
+ RIGHT_BRACE = 331,
+ DOT = 332,
+ COMMA = 333,
+ COLON = 334,
+ EQUAL = 335,
+ SEMICOLON = 336,
+ BANG = 337,
+ DASH = 338,
+ TILDE = 339,
+ PLUS = 340,
+ STAR = 341,
+ SLASH = 342,
+ PERCENT = 343,
+ LEFT_ANGLE = 344,
+ RIGHT_ANGLE = 345,
+ VERTICAL_BAR = 346,
+ CARET = 347,
+ AMPERSAND = 348,
+ QUESTION = 349
+ };
+#endif
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+
+ struct {
+ union {
+ TString *string;
+ float f;
+ int i;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TField* field;
+ TFieldList* fieldList;
+ };
+ } interm;
+
+
+
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (TParseContext* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */
+
+/* Copy the second part of user declarations. */
+
+
+extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner);
+static void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason);
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (YYID(N)) { \
+ (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).last_file = YYRHSLOC(Rhs, N).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ } \
+ else { \
+ (Current).first_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).first_line = YYRHSLOC(Rhs, 0).last_line; \
+ (Current).last_file = YYRHSLOC(Rhs, 0).last_file; \
+ (Current).last_line = YYRHSLOC(Rhs, 0).last_line; \
+ } \
+ } while (0)
+
+#define VERTEX_ONLY(S, L) { \
+ if (context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only ", S); \
+ context->recover(); \
+ } \
+}
+
+#define FRAG_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER) { \
+ context->error(L, " supported in fragment shaders only ", S); \
+ context->recover(); \
+ } \
+}
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(N) (N)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+ YYLTYPE yyls_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
+ + 2 * YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 74
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 1490
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 95
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 84
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 202
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 307
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 349
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 11, 13, 15, 17,
+ 21, 23, 28, 30, 34, 37, 40, 42, 44, 46,
+ 50, 53, 56, 59, 61, 64, 68, 71, 73, 75,
+ 77, 80, 83, 86, 88, 90, 92, 94, 98, 102,
+ 104, 108, 112, 114, 116, 120, 124, 128, 132, 134,
+ 138, 142, 144, 146, 148, 150, 154, 156, 160, 162,
+ 166, 168, 174, 176, 180, 182, 184, 186, 188, 190,
+ 192, 196, 198, 201, 204, 209, 212, 214, 216, 219,
+ 223, 227, 230, 236, 240, 243, 247, 250, 251, 253,
+ 255, 257, 259, 261, 265, 271, 278, 284, 286, 289,
+ 294, 300, 305, 308, 310, 313, 315, 317, 319, 322,
+ 324, 326, 329, 331, 333, 335, 337, 342, 344, 346,
+ 348, 350, 352, 354, 356, 358, 360, 362, 364, 366,
+ 368, 370, 372, 374, 376, 378, 380, 382, 384, 386,
+ 387, 394, 395, 401, 403, 406, 410, 412, 416, 418,
+ 423, 425, 427, 429, 431, 433, 435, 437, 439, 441,
+ 444, 445, 446, 452, 454, 456, 457, 460, 461, 464,
+ 467, 471, 473, 476, 478, 481, 487, 491, 493, 495,
+ 500, 501, 508, 509, 518, 519, 527, 529, 531, 533,
+ 534, 537, 541, 544, 547, 550, 554, 557, 559, 562,
+ 564, 566, 567
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 175, 0, -1, 45, -1, 46, -1, 45, -1, 97,
+ -1, 48, -1, 47, -1, 49, -1, 71, 124, 72,
+ -1, 98, -1, 99, 73, 100, 74, -1, 101, -1,
+ 99, 77, 96, -1, 99, 52, -1, 99, 53, -1,
+ 124, -1, 102, -1, 103, -1, 99, 77, 103, -1,
+ 105, 72, -1, 104, 72, -1, 106, 39, -1, 106,
+ -1, 106, 122, -1, 105, 78, 122, -1, 107, 71,
+ -1, 142, -1, 45, -1, 99, -1, 52, 108, -1,
+ 53, 108, -1, 109, 108, -1, 85, -1, 83, -1,
+ 82, -1, 108, -1, 110, 86, 108, -1, 110, 87,
+ 108, -1, 110, -1, 111, 85, 110, -1, 111, 83,
+ 110, -1, 111, -1, 112, -1, 113, 89, 112, -1,
+ 113, 90, 112, -1, 113, 54, 112, -1, 113, 55,
+ 112, -1, 113, -1, 114, 56, 113, -1, 114, 57,
+ 113, -1, 114, -1, 115, -1, 116, -1, 117, -1,
+ 118, 58, 117, -1, 118, -1, 119, 60, 118, -1,
+ 119, -1, 120, 59, 119, -1, 120, -1, 120, 94,
+ 124, 79, 122, -1, 121, -1, 108, 123, 122, -1,
+ 80, -1, 61, -1, 62, -1, 63, -1, 70, -1,
+ 122, -1, 124, 78, 122, -1, 121, -1, 127, 81,
+ -1, 135, 81, -1, 7, 140, 141, 81, -1, 128,
+ 72, -1, 130, -1, 129, -1, 130, 132, -1, 129,
+ 78, 132, -1, 137, 45, 71, -1, 139, 96, -1,
+ 139, 96, 73, 125, 74, -1, 138, 133, 131, -1,
+ 133, 131, -1, 138, 133, 134, -1, 133, 134, -1,
+ -1, 33, -1, 34, -1, 35, -1, 139, -1, 136,
+ -1, 135, 78, 96, -1, 135, 78, 96, 73, 74,
+ -1, 135, 78, 96, 73, 125, 74, -1, 135, 78,
+ 96, 80, 150, -1, 137, -1, 137, 96, -1, 137,
+ 96, 73, 74, -1, 137, 96, 73, 125, 74, -1,
+ 137, 96, 80, 150, -1, 3, 45, -1, 139, -1,
+ 138, 139, -1, 9, -1, 8, -1, 37, -1, 3,
+ 37, -1, 36, -1, 141, -1, 140, 141, -1, 4,
+ -1, 5, -1, 6, -1, 142, -1, 142, 73, 125,
+ 74, -1, 39, -1, 11, -1, 12, -1, 10, -1,
+ 27, -1, 28, -1, 29, -1, 21, -1, 22, -1,
+ 23, -1, 24, -1, 25, -1, 26, -1, 30, -1,
+ 31, -1, 32, -1, 41, -1, 42, -1, 43, -1,
+ 44, -1, 143, -1, 46, -1, -1, 38, 96, 75,
+ 144, 146, 76, -1, -1, 38, 75, 145, 146, 76,
+ -1, 147, -1, 146, 147, -1, 139, 148, 81, -1,
+ 149, -1, 148, 78, 149, -1, 96, -1, 96, 73,
+ 125, 74, -1, 122, -1, 126, -1, 154, -1, 153,
+ -1, 151, -1, 163, -1, 164, -1, 167, -1, 174,
+ -1, 75, 76, -1, -1, -1, 75, 155, 162, 156,
+ 76, -1, 161, -1, 153, -1, -1, 159, 161, -1,
+ -1, 160, 153, -1, 75, 76, -1, 75, 162, 76,
+ -1, 152, -1, 162, 152, -1, 81, -1, 124, 81,
+ -1, 18, 71, 124, 72, 165, -1, 158, 16, 158,
+ -1, 158, -1, 124, -1, 137, 96, 80, 150, -1,
+ -1, 40, 71, 168, 166, 72, 157, -1, -1, 15,
+ 169, 158, 40, 71, 124, 72, 81, -1, -1, 17,
+ 71, 170, 171, 173, 72, 157, -1, 163, -1, 151,
+ -1, 166, -1, -1, 172, 81, -1, 172, 81, 124,
+ -1, 14, 81, -1, 13, 81, -1, 20, 81, -1,
+ 20, 124, 81, -1, 19, 81, -1, 176, -1, 175,
+ 176, -1, 177, -1, 126, -1, -1, 127, 178, 161,
+ -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 179, 179, 180, 183, 226, 229, 242, 247, 252,
+ 258, 261, 264, 267, 362, 372, 385, 393, 493, 496,
+ 504, 507, 513, 517, 524, 530, 539, 547, 602, 612,
+ 615, 625, 635, 656, 657, 658, 663, 664, 672, 683,
+ 684, 692, 703, 707, 708, 718, 728, 738, 751, 752,
+ 762, 775, 779, 783, 787, 788, 801, 802, 815, 816,
+ 829, 830, 847, 848, 861, 862, 863, 864, 865, 869,
+ 872, 883, 891, 918, 923, 937, 992, 995, 1002, 1010,
+ 1031, 1052, 1062, 1090, 1095, 1105, 1110, 1120, 1123, 1126,
+ 1129, 1135, 1142, 1145, 1167, 1185, 1209, 1232, 1236, 1254,
+ 1262, 1294, 1314, 1335, 1344, 1367, 1370, 1376, 1384, 1392,
+ 1400, 1410, 1417, 1420, 1423, 1429, 1432, 1447, 1451, 1455,
+ 1459, 1463, 1468, 1473, 1478, 1483, 1488, 1493, 1498, 1503,
+ 1508, 1513, 1518, 1523, 1527, 1531, 1539, 1547, 1551, 1564,
+ 1564, 1578, 1578, 1587, 1590, 1606, 1639, 1643, 1649, 1656,
+ 1671, 1675, 1679, 1680, 1686, 1687, 1688, 1689, 1690, 1694,
+ 1695, 1695, 1695, 1705, 1706, 1710, 1710, 1711, 1711, 1716,
+ 1719, 1729, 1732, 1738, 1739, 1743, 1751, 1755, 1765, 1770,
+ 1787, 1787, 1792, 1792, 1799, 1799, 1807, 1810, 1816, 1819,
+ 1825, 1829, 1836, 1843, 1850, 1857, 1868, 1877, 1881, 1888,
+ 1891, 1897, 1897
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INVARIANT", "HIGH_PRECISION",
+ "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "ATTRIBUTE",
+ "CONST_QUAL", "BOOL_TYPE", "FLOAT_TYPE", "INT_TYPE", "BREAK", "CONTINUE",
+ "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN", "BVEC2", "BVEC3",
+ "BVEC4", "IVEC2", "IVEC3", "IVEC4", "VEC2", "VEC3", "VEC4", "MATRIX2",
+ "MATRIX3", "MATRIX4", "IN_QUAL", "OUT_QUAL", "INOUT_QUAL", "UNIFORM",
+ "VARYING", "STRUCT", "VOID_TYPE", "WHILE", "SAMPLER2D", "SAMPLERCUBE",
+ "SAMPLER_EXTERNAL_OES", "SAMPLER2DRECT", "IDENTIFIER", "TYPE_NAME",
+ "FLOATCONSTANT", "INTCONSTANT", "BOOLCONSTANT", "LEFT_OP", "RIGHT_OP",
+ "INC_OP", "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", "AND_OP",
+ "OR_OP", "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN",
+ "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN",
+ "OR_ASSIGN", "SUB_ASSIGN", "LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACKET",
+ "RIGHT_BRACKET", "LEFT_BRACE", "RIGHT_BRACE", "DOT", "COMMA", "COLON",
+ "EQUAL", "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS", "STAR", "SLASH",
+ "PERCENT", "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR", "CARET",
+ "AMPERSAND", "QUESTION", "$accept", "identifier", "variable_identifier",
+ "primary_expression", "postfix_expression", "integer_expression",
+ "function_call", "function_call_or_method", "function_call_generic",
+ "function_call_header_no_parameters",
+ "function_call_header_with_parameters", "function_call_header",
+ "function_identifier", "unary_expression", "unary_operator",
+ "multiplicative_expression", "additive_expression", "shift_expression",
+ "relational_expression", "equality_expression", "and_expression",
+ "exclusive_or_expression", "inclusive_or_expression",
+ "logical_and_expression", "logical_xor_expression",
+ "logical_or_expression", "conditional_expression",
+ "assignment_expression", "assignment_operator", "expression",
+ "constant_expression", "declaration", "function_prototype",
+ "function_declarator", "function_header_with_parameters",
+ "function_header", "parameter_declarator", "parameter_declaration",
+ "parameter_qualifier", "parameter_type_specifier",
+ "init_declarator_list", "single_declaration", "fully_specified_type",
+ "type_qualifier", "type_specifier", "precision_qualifier",
+ "type_specifier_no_prec", "type_specifier_nonarray", "struct_specifier",
+ "$@1", "$@2", "struct_declaration_list", "struct_declaration",
+ "struct_declarator_list", "struct_declarator", "initializer",
+ "declaration_statement", "statement", "simple_statement",
+ "compound_statement", "$@3", "$@4", "statement_no_new_scope",
+ "statement_with_scope", "$@5", "$@6", "compound_statement_no_new_scope",
+ "statement_list", "expression_statement", "selection_statement",
+ "selection_rest_statement", "condition", "iteration_statement", "$@7",
+ "$@8", "$@9", "for_init_statement", "conditionopt", "for_rest_statement",
+ "jump_statement", "translation_unit", "external_declaration",
+ "function_definition", "$@10", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 95, 96, 96, 97, 98, 98, 98, 98, 98,
+ 99, 99, 99, 99, 99, 99, 100, 101, 102, 102,
+ 103, 103, 104, 104, 105, 105, 106, 107, 107, 108,
+ 108, 108, 108, 109, 109, 109, 110, 110, 110, 111,
+ 111, 111, 112, 113, 113, 113, 113, 113, 114, 114,
+ 114, 115, 116, 117, 118, 118, 119, 119, 120, 120,
+ 121, 121, 122, 122, 123, 123, 123, 123, 123, 124,
+ 124, 125, 126, 126, 126, 127, 128, 128, 129, 129,
+ 130, 131, 131, 132, 132, 132, 132, 133, 133, 133,
+ 133, 134, 135, 135, 135, 135, 135, 136, 136, 136,
+ 136, 136, 136, 137, 137, 138, 138, 138, 138, 138,
+ 139, 139, 140, 140, 140, 141, 141, 142, 142, 142,
+ 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+ 142, 142, 142, 142, 142, 142, 142, 142, 142, 144,
+ 143, 145, 143, 146, 146, 147, 148, 148, 149, 149,
+ 150, 151, 152, 152, 153, 153, 153, 153, 153, 154,
+ 155, 156, 154, 157, 157, 159, 158, 160, 158, 161,
+ 161, 162, 162, 163, 163, 164, 165, 165, 166, 166,
+ 168, 167, 169, 167, 170, 167, 171, 171, 172, 172,
+ 173, 173, 174, 174, 174, 174, 174, 175, 175, 176,
+ 176, 178, 177
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 1, 1, 1, 1, 1, 1, 3,
+ 1, 4, 1, 3, 2, 2, 1, 1, 1, 3,
+ 2, 2, 2, 1, 2, 3, 2, 1, 1, 1,
+ 2, 2, 2, 1, 1, 1, 1, 3, 3, 1,
+ 3, 3, 1, 1, 3, 3, 3, 3, 1, 3,
+ 3, 1, 1, 1, 1, 3, 1, 3, 1, 3,
+ 1, 5, 1, 3, 1, 1, 1, 1, 1, 1,
+ 3, 1, 2, 2, 4, 2, 1, 1, 2, 3,
+ 3, 2, 5, 3, 2, 3, 2, 0, 1, 1,
+ 1, 1, 1, 3, 5, 6, 5, 1, 2, 4,
+ 5, 4, 2, 1, 2, 1, 1, 1, 2, 1,
+ 1, 2, 1, 1, 1, 1, 4, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+ 6, 0, 5, 1, 2, 3, 1, 3, 1, 4,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 0, 0, 5, 1, 1, 0, 2, 0, 2, 2,
+ 3, 1, 2, 1, 2, 5, 3, 1, 1, 4,
+ 0, 6, 0, 8, 0, 7, 1, 1, 1, 0,
+ 2, 3, 2, 2, 2, 3, 2, 1, 2, 1,
+ 1, 0, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 0, 112, 113, 114, 0, 106, 105, 120, 118,
+ 119, 124, 125, 126, 127, 128, 129, 121, 122, 123,
+ 130, 131, 132, 109, 107, 0, 117, 133, 134, 135,
+ 136, 138, 200, 201, 0, 77, 87, 0, 92, 97,
+ 0, 103, 0, 110, 115, 137, 0, 197, 199, 108,
+ 102, 0, 2, 3, 141, 0, 72, 0, 75, 87,
+ 0, 88, 89, 90, 78, 0, 87, 0, 73, 2,
+ 98, 104, 111, 0, 1, 198, 0, 0, 139, 0,
+ 202, 79, 84, 86, 91, 0, 93, 80, 0, 0,
+ 4, 7, 6, 8, 0, 0, 0, 35, 34, 33,
+ 5, 10, 29, 12, 17, 18, 0, 0, 23, 0,
+ 36, 0, 39, 42, 43, 48, 51, 52, 53, 54,
+ 56, 58, 60, 71, 0, 27, 74, 0, 0, 143,
+ 0, 0, 0, 182, 0, 0, 0, 0, 0, 160,
+ 169, 173, 36, 62, 69, 0, 151, 0, 115, 154,
+ 171, 153, 152, 0, 155, 156, 157, 158, 81, 83,
+ 85, 0, 0, 99, 0, 150, 101, 30, 31, 0,
+ 14, 15, 0, 0, 21, 20, 0, 22, 24, 26,
+ 32, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 116, 148, 0, 146, 142,
+ 144, 0, 193, 192, 167, 184, 0, 196, 194, 0,
+ 180, 159, 0, 65, 66, 67, 68, 64, 0, 0,
+ 174, 170, 172, 0, 94, 0, 96, 100, 9, 0,
+ 16, 2, 3, 13, 19, 25, 37, 38, 41, 40,
+ 46, 47, 44, 45, 49, 50, 55, 57, 59, 0,
+ 0, 0, 145, 140, 0, 0, 0, 0, 0, 195,
+ 0, 161, 63, 70, 0, 95, 11, 0, 0, 147,
+ 0, 166, 168, 187, 186, 189, 167, 178, 0, 0,
+ 0, 82, 61, 149, 0, 188, 0, 0, 177, 175,
+ 0, 0, 162, 0, 190, 0, 167, 0, 164, 181,
+ 163, 0, 191, 185, 176, 179, 183
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 196, 100, 101, 102, 229, 103, 104, 105, 106,
+ 107, 108, 109, 142, 111, 112, 113, 114, 115, 116,
+ 117, 118, 119, 120, 121, 122, 143, 144, 218, 145,
+ 124, 146, 147, 34, 35, 36, 82, 64, 65, 83,
+ 37, 38, 39, 40, 41, 42, 43, 125, 45, 130,
+ 77, 128, 129, 197, 198, 166, 149, 150, 151, 152,
+ 212, 280, 299, 254, 255, 256, 300, 153, 154, 155,
+ 289, 279, 156, 260, 204, 257, 275, 286, 287, 157,
+ 46, 47, 48, 57
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -261
+static const yytype_int16 yypact[] =
+{
+ 1327, -20, -261, -261, -261, 113, -261, -261, -261, -261,
+ -261, -261, -261, -261, -261, -261, -261, -261, -261, -261,
+ -261, -261, -261, -261, -261, -19, -261, -261, -261, -261,
+ -261, -261, -261, -61, -40, -28, 75, -7, -261, 24,
+ 1370, -261, 1444, -261, -11, -261, 1283, -261, -261, -261,
+ -261, 1444, -261, -261, -261, 6, -261, 54, -261, 88,
+ 62, -261, -261, -261, -261, 1370, 59, 91, -261, 36,
+ -50, -261, -261, 1051, -261, -261, 63, 1370, -261, 293,
+ -261, -261, -261, -261, 91, 1370, -12, -261, 856, 1051,
+ 77, -261, -261, -261, 1051, 1051, 1051, -261, -261, -261,
+ -261, -261, -14, -261, -261, -261, 84, -44, 1116, 95,
+ -261, 1051, 53, 3, -261, -36, 89, -261, -261, -261,
+ 104, 107, -45, -261, 96, -261, -261, 91, 1184, -261,
+ 1370, 92, 93, -261, 98, 101, 94, 921, 105, 102,
+ -261, -261, 72, -261, -261, 9, -261, -61, 42, -261,
+ -261, -261, -261, 376, -261, -261, -261, -261, 106, -261,
+ -261, 986, 1051, -261, 103, -261, -261, -261, -261, -41,
+ -261, -261, 1051, 1407, -261, -261, 1051, 110, -261, -261,
+ -261, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051, 1051,
+ 1051, 1051, 1051, 1051, 1051, -261, 109, 23, -261, -261,
+ -261, 1227, -261, -261, 111, -261, 1051, -261, -261, 25,
+ -261, -261, 459, -261, -261, -261, -261, -261, 1051, 1051,
+ -261, -261, -261, 1051, -261, 114, -261, -261, -261, 115,
+ 112, 77, 116, -261, -261, -261, -261, -261, 53, 53,
+ -261, -261, -261, -261, -36, -36, -261, 104, 107, 76,
+ 1051, 91, -261, -261, 145, 54, 625, 708, -6, -261,
+ 791, 459, -261, -261, 117, -261, -261, 1051, 120, -261,
+ 124, -261, -261, -261, -261, 791, 111, 112, 91, 125,
+ 122, -261, -261, -261, 1051, -261, 118, 128, 180, -261,
+ 126, 542, -261, -5, 1051, 542, 111, 1051, -261, -261,
+ -261, 123, 112, -261, -261, -261, -261
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -261, -24, -261, -261, -261, -261, -261, -261, 34, -261,
+ -261, -261, -261, 32, -261, -33, -261, -27, -26, -261,
+ -261, -261, 14, 16, 18, -261, -66, -87, -261, -92,
+ -85, 11, 12, -261, -261, -261, 141, 150, 161, 143,
+ -261, -261, -231, 5, -30, 224, -18, 0, -261, -261,
+ -261, 100, -119, -261, -17, -156, -25, -145, -243, -261,
+ -261, -261, -64, -260, -261, -261, -52, 21, -22, -261,
+ -261, -39, -261, -261, -261, -261, -261, -261, -261, -261,
+ -261, 191, -261, -261
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -166
+static const yytype_int16 yytable[] =
+{
+ 44, 55, 165, 164, 169, 80, 226, 123, 222, 200,
+ 71, 32, 33, 272, 193, 70, 288, 49, 185, 186,
+ 56, 178, 123, 88, 72, 50, 52, 53, 175, 278,
+ 89, 228, 58, 76, 176, 84, 304, 219, 170, 171,
+ 44, 66, 44, 86, 278, 209, 44, 127, 298, 194,
+ 59, 44, 298, 187, 188, 84, 54, 32, 33, 172,
+ 158, 161, 73, 173, 66, 44, 276, 301, 162, 69,
+ 53, 67, 219, 219, 68, 165, 225, 44, 60, 148,
+ 230, 78, 200, 6, 7, 44, 183, 219, 184, 235,
+ 220, 60, 61, 62, 63, 123, 6, 7, 127, 49,
+ 127, 251, 249, 219, 252, 110, 259, 87, 61, 62,
+ 63, 23, 24, -27, 258, 73, 222, 2, 3, 4,
+ 110, 61, 62, 63, 23, 24, 167, 168, 44, 79,
+ 44, 262, 263, 213, 214, 215, 52, 53, 264, 181,
+ 182, 305, 216, 180, 126, 189, 190, -76, -28, 233,
+ 238, 239, 217, 148, 219, 267, 174, 123, 240, 241,
+ 242, 243, 191, 244, 245, 268, 179, 192, 277, 205,
+ 195, 127, 206, 202, 203, 207, 210, 227, 211, 223,
+ 282, -117, 250, 277, 123, 270, -165, -138, 265, 266,
+ 219, 281, 293, 110, 283, 284, 296, 291, 292, 294,
+ 295, 44, 302, 271, 306, 246, 297, 234, 247, 81,
+ 165, 248, 148, 236, 237, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 159, 85, 160, 51,
+ 201, 303, 273, 261, 269, 274, 285, 75, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 290, 110, 148, 148, 0, 0,
+ 148, 148, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 148, 0, 0, 0, 0,
+ 0, 0, 110, 0, 0, 0, 0, 0, 0, 0,
+ 0, 148, 0, 0, 0, 148, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 131, 132, 133, 0,
+ 134, 135, 136, 137, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 0, 0, 0, 23,
+ 24, 25, 26, 138, 27, 28, 29, 30, 90, 31,
+ 91, 92, 93, 0, 0, 94, 95, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 96, 0, 0, 0, 139, 140,
+ 0, 0, 0, 0, 141, 97, 98, 0, 99, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 131,
+ 132, 133, 0, 134, 135, 136, 137, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 0,
+ 0, 0, 23, 24, 25, 26, 138, 27, 28, 29,
+ 30, 90, 31, 91, 92, 93, 0, 0, 94, 95,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 96, 0, 0,
+ 0, 139, 221, 0, 0, 0, 0, 141, 97, 98,
+ 0, 99, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 131, 132, 133, 0, 134, 135, 136, 137,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 0, 0, 0, 23, 24, 25, 26, 138,
+ 27, 28, 29, 30, 90, 31, 91, 92, 93, 0,
+ 0, 94, 95, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 96, 0, 0, 0, 139, 0, 0, 0, 0, 0,
+ 141, 97, 98, 0, 99, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 131, 132, 133, 0, 134,
+ 135, 136, 137, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 0, 0, 0, 23, 24,
+ 25, 26, 138, 27, 28, 29, 30, 90, 31, 91,
+ 92, 93, 0, 0, 94, 95, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 96, 0, 0, 0, 79, 0, 0,
+ 0, 0, 0, 141, 97, 98, 0, 99, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 131, 132,
+ 133, 0, 134, 135, 136, 137, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 0, 0,
+ 0, 23, 24, 25, 26, 138, 27, 28, 29, 30,
+ 90, 31, 91, 92, 93, 0, 0, 94, 95, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 96, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 141, 97, 98, 0,
+ 99, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 0, 0, 0, 0, 0, 0, 0, 0, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 0, 0, 0, 23, 24, 25, 26, 0, 27,
+ 28, 29, 30, 90, 31, 91, 92, 93, 0, 0,
+ 94, 95, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 96,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 141,
+ 97, 98, 0, 99, 60, 2, 3, 4, 0, 6,
+ 7, 8, 9, 10, 0, 0, 0, 0, 0, 0,
+ 0, 0, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 0, 0, 0, 23, 24, 25,
+ 26, 0, 27, 28, 29, 30, 90, 31, 91, 92,
+ 93, 0, 0, 94, 95, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 96, 0, 0, 0, 8, 9, 10, 0,
+ 0, 0, 0, 97, 98, 0, 99, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 0,
+ 0, 0, 0, 0, 25, 26, 0, 27, 28, 29,
+ 30, 90, 31, 91, 92, 93, 0, 0, 94, 95,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 96, 0, 0,
+ 163, 8, 9, 10, 0, 0, 0, 0, 97, 98,
+ 0, 99, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 0, 0, 0, 0, 0, 25,
+ 26, 0, 27, 28, 29, 30, 90, 31, 91, 92,
+ 93, 0, 0, 94, 95, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 96, 0, 0, 0, 8, 9, 10, 0,
+ 0, 0, 208, 97, 98, 0, 99, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 0,
+ 0, 0, 0, 0, 25, 26, 0, 27, 28, 29,
+ 30, 90, 31, 91, 92, 93, 0, 0, 94, 95,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 96, 0, 0,
+ 224, 8, 9, 10, 0, 0, 0, 0, 97, 98,
+ 0, 99, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 0, 0, 0, 0, 0, 25,
+ 26, 0, 27, 28, 29, 30, 90, 31, 91, 92,
+ 93, 0, 0, 94, 95, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 96, 0, 0, 0, 8, 9, 10, 0,
+ 0, 0, 0, 97, 98, 0, 99, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 0,
+ 0, 0, 0, 0, 25, 177, 0, 27, 28, 29,
+ 30, 90, 31, 91, 92, 93, 0, 0, 94, 95,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 96, 2, 3,
+ 4, 0, 0, 0, 8, 9, 10, 0, 97, 98,
+ 0, 99, 0, 0, 0, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 0, 0, 0,
+ 0, 0, 25, 26, 0, 27, 28, 29, 30, 0,
+ 31, 2, 3, 4, 0, 0, 0, 8, 9, 10,
+ 0, 0, 0, 0, 0, 0, 0, 0, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 199, 0, 0, 0, 0, 25, 26, 0, 27, 28,
+ 29, 30, 0, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 74, 0, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 0, 0, 0, 0,
+ 0, 0, 0, 253, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 0, 0, 0, 23,
+ 24, 25, 26, 0, 27, 28, 29, 30, 0, 31,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 0, 0, 0, 0, 0, 0, 0, 0, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 0, 0, 0, 23, 24, 25, 26, 0, 27, 28,
+ 29, 30, 0, 31, 2, 3, 4, 0, 0, 0,
+ 8, 9, 10, 0, 0, 0, 0, 0, 0, 0,
+ 0, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 0, 0, 0, 0, 0, 25, 26,
+ 0, 27, 28, 29, 30, 0, 31, 8, 9, 10,
+ 0, 0, 0, 0, 0, 0, 0, 0, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 0, 0, 0, 0, 0, 25, 26, 0, 27, 28,
+ 29, 30, 231, 232, 8, 9, 10, 0, 0, 0,
+ 0, 0, 0, 0, 0, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 0, 0, 0,
+ 0, 0, 25, 26, 0, 27, 28, 29, 30, 0,
+ 31
+};
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-261)))
+
+#define yytable_value_is_error(Yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 0, 25, 89, 88, 96, 57, 162, 73, 153, 128,
+ 40, 0, 0, 256, 59, 39, 276, 37, 54, 55,
+ 81, 108, 88, 73, 42, 45, 45, 46, 72, 260,
+ 80, 72, 72, 51, 78, 65, 296, 78, 52, 53,
+ 40, 36, 42, 67, 275, 137, 46, 77, 291, 94,
+ 78, 51, 295, 89, 90, 85, 75, 46, 46, 73,
+ 84, 73, 73, 77, 59, 65, 72, 72, 80, 45,
+ 46, 78, 78, 78, 81, 162, 161, 77, 3, 79,
+ 172, 75, 201, 8, 9, 85, 83, 78, 85, 176,
+ 81, 3, 33, 34, 35, 161, 8, 9, 128, 37,
+ 130, 78, 194, 78, 81, 73, 81, 71, 33, 34,
+ 35, 36, 37, 71, 206, 73, 261, 4, 5, 6,
+ 88, 33, 34, 35, 36, 37, 94, 95, 128, 75,
+ 130, 218, 219, 61, 62, 63, 45, 46, 223, 86,
+ 87, 297, 70, 111, 81, 56, 57, 72, 71, 173,
+ 183, 184, 80, 153, 78, 79, 72, 223, 185, 186,
+ 187, 188, 58, 189, 190, 250, 71, 60, 260, 71,
+ 74, 201, 71, 81, 81, 81, 71, 74, 76, 73,
+ 267, 71, 73, 275, 250, 40, 75, 71, 74, 74,
+ 78, 74, 284, 161, 74, 71, 16, 72, 76, 81,
+ 72, 201, 294, 255, 81, 191, 80, 173, 192, 59,
+ 297, 193, 212, 181, 182, 183, 184, 185, 186, 187,
+ 188, 189, 190, 191, 192, 193, 85, 66, 85, 5,
+ 130, 295, 257, 212, 251, 257, 275, 46, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 278, 223, 256, 257, -1, -1,
+ 260, 261, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 275, -1, -1, -1, -1,
+ -1, -1, 250, -1, -1, -1, -1, -1, -1, -1,
+ -1, 291, -1, -1, -1, 295, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, -1,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, -1, -1, -1, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, -1, -1, 52, 53, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 71, -1, -1, -1, 75, 76,
+ -1, -1, -1, -1, 81, 82, 83, -1, 85, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, -1, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, -1,
+ -1, -1, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, -1, -1, 52, 53,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 71, -1, -1,
+ -1, 75, 76, -1, -1, -1, -1, 81, 82, 83,
+ -1, 85, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, -1, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, -1, -1, -1, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, -1,
+ -1, 52, 53, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 71, -1, -1, -1, 75, -1, -1, -1, -1, -1,
+ 81, 82, 83, -1, 85, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, -1, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, -1, -1, -1, 36, 37,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, -1, -1, 52, 53, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 71, -1, -1, -1, 75, -1, -1,
+ -1, -1, -1, 81, 82, 83, -1, 85, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, -1, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, -1, -1,
+ -1, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, -1, -1, 52, 53, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 71, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 81, 82, 83, -1,
+ 85, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, -1, -1, -1, -1, -1, -1, -1, -1, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, -1, -1, -1, 36, 37, 38, 39, -1, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, -1, -1,
+ 52, 53, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 71,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 81,
+ 82, 83, -1, 85, 3, 4, 5, 6, -1, 8,
+ 9, 10, 11, 12, -1, -1, -1, -1, -1, -1,
+ -1, -1, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, -1, -1, -1, 36, 37, 38,
+ 39, -1, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, -1, -1, 52, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 71, -1, -1, -1, 10, 11, 12, -1,
+ -1, -1, -1, 82, 83, -1, 85, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, -1,
+ -1, -1, -1, -1, 38, 39, -1, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, -1, -1, 52, 53,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 71, -1, -1,
+ 74, 10, 11, 12, -1, -1, -1, -1, 82, 83,
+ -1, 85, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, -1, -1, -1, -1, -1, 38,
+ 39, -1, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, -1, -1, 52, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 71, -1, -1, -1, 10, 11, 12, -1,
+ -1, -1, 81, 82, 83, -1, 85, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, -1,
+ -1, -1, -1, -1, 38, 39, -1, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, -1, -1, 52, 53,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 71, -1, -1,
+ 74, 10, 11, 12, -1, -1, -1, -1, 82, 83,
+ -1, 85, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, -1, -1, -1, -1, -1, 38,
+ 39, -1, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, -1, -1, 52, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 71, -1, -1, -1, 10, 11, 12, -1,
+ -1, -1, -1, 82, 83, -1, 85, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, -1,
+ -1, -1, -1, -1, 38, 39, -1, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, -1, -1, 52, 53,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 71, 4, 5,
+ 6, -1, -1, -1, 10, 11, 12, -1, 82, 83,
+ -1, 85, -1, -1, -1, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, -1, -1, -1,
+ -1, -1, 38, 39, -1, 41, 42, 43, 44, -1,
+ 46, 4, 5, 6, -1, -1, -1, 10, 11, 12,
+ -1, -1, -1, -1, -1, -1, -1, -1, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 76, -1, -1, -1, -1, 38, 39, -1, 41, 42,
+ 43, 44, -1, 46, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 0, -1, -1, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, -1, -1, -1, -1,
+ -1, -1, -1, 76, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, -1, -1, -1, 36,
+ 37, 38, 39, -1, 41, 42, 43, 44, -1, 46,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ -1, -1, -1, -1, -1, -1, -1, -1, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ -1, -1, -1, 36, 37, 38, 39, -1, 41, 42,
+ 43, 44, -1, 46, 4, 5, 6, -1, -1, -1,
+ 10, 11, 12, -1, -1, -1, -1, -1, -1, -1,
+ -1, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, -1, -1, -1, -1, -1, 38, 39,
+ -1, 41, 42, 43, 44, -1, 46, 10, 11, 12,
+ -1, -1, -1, -1, -1, -1, -1, -1, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ -1, -1, -1, -1, -1, 38, 39, -1, 41, 42,
+ 43, 44, 45, 46, 10, 11, 12, -1, -1, -1,
+ -1, -1, -1, -1, -1, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, -1, -1, -1,
+ -1, -1, 38, 39, -1, 41, 42, 43, 44, -1,
+ 46
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 36, 37, 38, 39, 41, 42, 43,
+ 44, 46, 126, 127, 128, 129, 130, 135, 136, 137,
+ 138, 139, 140, 141, 142, 143, 175, 176, 177, 37,
+ 45, 140, 45, 46, 75, 96, 81, 178, 72, 78,
+ 3, 33, 34, 35, 132, 133, 138, 78, 81, 45,
+ 96, 139, 141, 73, 0, 176, 141, 145, 75, 75,
+ 161, 132, 131, 134, 139, 133, 96, 71, 73, 80,
+ 45, 47, 48, 49, 52, 53, 71, 82, 83, 85,
+ 97, 98, 99, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+ 118, 119, 120, 121, 125, 142, 81, 139, 146, 147,
+ 144, 13, 14, 15, 17, 18, 19, 20, 40, 75,
+ 76, 81, 108, 121, 122, 124, 126, 127, 142, 151,
+ 152, 153, 154, 162, 163, 164, 167, 174, 96, 131,
+ 134, 73, 80, 74, 125, 122, 150, 108, 108, 124,
+ 52, 53, 73, 77, 72, 72, 78, 39, 122, 71,
+ 108, 86, 87, 83, 85, 54, 55, 89, 90, 56,
+ 57, 58, 60, 59, 94, 74, 96, 148, 149, 76,
+ 147, 146, 81, 81, 169, 71, 71, 81, 81, 124,
+ 71, 76, 155, 61, 62, 63, 70, 80, 123, 78,
+ 81, 76, 152, 73, 74, 125, 150, 74, 72, 100,
+ 124, 45, 46, 96, 103, 122, 108, 108, 110, 110,
+ 112, 112, 112, 112, 113, 113, 117, 118, 119, 124,
+ 73, 78, 81, 76, 158, 159, 160, 170, 124, 81,
+ 168, 162, 122, 122, 125, 74, 74, 79, 125, 149,
+ 40, 161, 153, 151, 163, 171, 72, 124, 137, 166,
+ 156, 74, 122, 74, 71, 166, 172, 173, 158, 165,
+ 96, 72, 76, 124, 81, 72, 16, 80, 153, 157,
+ 161, 72, 124, 157, 158, 150, 81
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+
+/* Print *YYLOCP on YYO. Private, do not rely on its existence. */
+
+__attribute__((__unused__))
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static unsigned
+yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
+#else
+static unsigned
+yy_location_print_ (yyo, yylocp)
+ FILE *yyo;
+ YYLTYPE const * const yylocp;
+#endif
+{
+ unsigned res = 0;
+ int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
+ if (0 <= yylocp->first_line)
+ {
+ res += fprintf (yyo, "%d", yylocp->first_line);
+ if (0 <= yylocp->first_column)
+ res += fprintf (yyo, ".%d", yylocp->first_column);
+ }
+ if (0 <= yylocp->last_line)
+ {
+ if (yylocp->first_line < yylocp->last_line)
+ {
+ res += fprintf (yyo, "-%d", yylocp->last_line);
+ if (0 <= end_col)
+ res += fprintf (yyo, ".%d", end_col);
+ }
+ else if (0 <= end_col && yylocp->first_column < end_col)
+ res += fprintf (yyo, "-%d", end_col);
+ }
+ return res;
+ }
+
+# define YY_LOCATION_PRINT(File, Loc) \
+ yy_location_print_ (File, &(Loc))
+
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, &yylloc)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, Location, context); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ YYLTYPE const * const yylocationp;
+ TParseContext* context;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+ YYUSE (yylocationp);
+ YYUSE (context);
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, TParseContext* context)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ YYLTYPE const * const yylocationp;
+ TParseContext* context;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ YY_LOCATION_PRINT (yyoutput, *yylocationp);
+ YYFPRINTF (yyoutput, ": ");
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, TParseContext* context)
+#else
+static void
+yy_reduce_print (yyvsp, yylsp, yyrule, context)
+ YYSTYPE *yyvsp;
+ YYLTYPE *yylsp;
+ int yyrule;
+ TParseContext* context;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , &(yylsp[(yyi + 1) - (yynrhs)]) , context);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, yylsp, Rule, context); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, TParseContext* context)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, yylocationp, context)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+ YYLTYPE *yylocationp;
+ TParseContext* context;
+#endif
+{
+ YYUSE (yyvaluep);
+ YYUSE (yylocationp);
+ YYUSE (context);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (TParseContext* context)
+#else
+int
+yyparse (context)
+ TParseContext* context;
+#endif
+#endif
+{
+/* The lookahead symbol. */
+int yychar;
+
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+static YYSTYPE yyval_default;
+# define YY_INITIAL_VALUE(Value) = Value
+#endif
+static YYLTYPE yyloc_default
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+ = { 1, 1, 1, 1 }
+# endif
+;
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
+
+/* Location data for the lookahead symbol. */
+YYLTYPE yylloc = yyloc_default;
+
+
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+ `yyls': related to locations.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ /* The location stack. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls;
+ YYLTYPE *yylsp;
+
+ /* The locations where the error started and ended. */
+ YYLTYPE yyerror_range[3];
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+ YYLTYPE yyloc;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yylsp = yyls = yylsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ yylsp[0] = yylloc;
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+ YYLTYPE *yyls1 = yyls;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yyls1, yysize * sizeof (*yylsp),
+ &yystacksize);
+
+ yyls = yyls1;
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyls_alloc, yyls);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+ yylsp = yyls + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+ *++yylsp = yylloc;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+ /* Default location. */
+ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+
+ {
+ // The symbol table search was done in the lexical phase
+ const TSymbol* symbol = (yyvsp[(1) - (1)].lex).symbol;
+ const TVariable* variable;
+ if (symbol == 0) {
+ context->error((yylsp[(1) - (1)]), "undeclared identifier", (yyvsp[(1) - (1)].lex).string->c_str());
+ context->recover();
+ TType type(EbtFloat, EbpUndefined);
+ TVariable* fakeVariable = new TVariable((yyvsp[(1) - (1)].lex).string, type);
+ context->symbolTable.insert(*fakeVariable);
+ variable = fakeVariable;
+ } else {
+ // This identifier can only be a variable type symbol
+ if (! symbol->isVariable()) {
+ context->error((yylsp[(1) - (1)]), "variable expected", (yyvsp[(1) - (1)].lex).string->c_str());
+ context->recover();
+ }
+
+ variable = static_cast<const TVariable*>(symbol);
+
+ if (context->symbolTable.findBuiltIn(variable->getName()) &&
+ !variable->getExtension().empty() &&
+ context->extensionErrorCheck((yylsp[(1) - (1)]), variable->getExtension())) {
+ context->recover();
+ }
+ }
+
+ // don't delete $1.string, it's used by error recovery, and the pool
+ // pop will reclaim the memory
+
+ if (variable->getType().getQualifier() == EvqConst ) {
+ ConstantUnion* constArray = variable->getConstPointer();
+ TType t(variable->getType());
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yylsp[(1) - (1)]));
+ } else
+ (yyval.interm.intermTypedNode) = context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(),
+ (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 5:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 6:
+
+ {
+ //
+ // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders,
+ // check for overflow for constants
+ //
+ if (abs((yyvsp[(1) - (1)].lex).i) >= (1 << 16)) {
+ context->error((yylsp[(1) - (1)]), " integer constant overflow", "");
+ context->recover();
+ }
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst((yyvsp[(1) - (1)].lex).i);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 7:
+
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst((yyvsp[(1) - (1)].lex).f);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 8:
+
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst((yyvsp[(1) - (1)].lex).b);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 9:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (3)].interm.intermTypedNode);
+ }
+ break;
+
+ case 10:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 11:
+
+ {
+ (yyval.interm.intermTypedNode) = context->addIndexExpression((yyvsp[(1) - (4)].interm.intermTypedNode), (yylsp[(2) - (4)]), (yyvsp[(3) - (4)].interm.intermTypedNode));
+ }
+ break;
+
+ case 12:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 13:
+
+ {
+ if ((yyvsp[(1) - (3)].interm.intermTypedNode)->isArray()) {
+ context->error((yylsp[(3) - (3)]), "cannot apply dot operator to an array", ".");
+ context->recover();
+ }
+
+ if ((yyvsp[(1) - (3)].interm.intermTypedNode)->isVector()) {
+ TVectorFields fields;
+ if (! context->parseVectorFields(*(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize(), fields, (yylsp[(3) - (3)]))) {
+ fields.num = 1;
+ fields.offsets[0] = 0;
+ context->recover();
+ }
+
+ if ((yyvsp[(1) - (3)].interm.intermTypedNode)->getType().getQualifier() == EvqConst) { // constant folding for vector fields
+ (yyval.interm.intermTypedNode) = context->addConstVectorNode(fields, (yyvsp[(1) - (3)].interm.intermTypedNode), (yylsp[(3) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ else
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision(), EvqConst, (int) (*(yyvsp[(3) - (3)].lex).string).size()));
+ } else {
+ TString vectorString = *(yyvsp[(3) - (3)].lex).string;
+ TIntermTyped* index = context->intermediate.addSwizzle(fields, (yylsp[(3) - (3)]));
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpVectorSwizzle, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yylsp[(2) - (3)]));
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision(), EvqTemporary, (int) vectorString.size()));
+ }
+ } else if ((yyvsp[(1) - (3)].interm.intermTypedNode)->isMatrix()) {
+ TMatrixFields fields;
+ if (! context->parseMatrixFields(*(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize(), fields, (yylsp[(3) - (3)]))) {
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = 0;
+ fields.col = 0;
+ context->recover();
+ }
+
+ if (fields.wholeRow || fields.wholeCol) {
+ context->error((yylsp[(2) - (3)]), " non-scalar fields not implemented yet", ".");
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(0);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yylsp[(3) - (3)]));
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yylsp[(2) - (3)]));
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision(),EvqTemporary, (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize()));
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.col * (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize() + fields.row);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yylsp[(3) - (3)]));
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yylsp[(2) - (3)]));
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision()));
+ }
+ } else if ((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType() == EbtStruct) {
+ bool fieldFound = false;
+ const TFieldList& fields = (yyvsp[(1) - (3)].interm.intermTypedNode)->getType().getStruct()->fields();
+ unsigned int i;
+ for (i = 0; i < fields.size(); ++i) {
+ if (fields[i]->name() == *(yyvsp[(3) - (3)].lex).string) {
+ fieldFound = true;
+ break;
+ }
+ }
+ if (fieldFound) {
+ if ((yyvsp[(1) - (3)].interm.intermTypedNode)->getType().getQualifier() == EvqConst) {
+ (yyval.interm.intermTypedNode) = context->addConstStruct(*(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ else {
+ (yyval.interm.intermTypedNode)->setType(*fields[i]->type());
+ // change the qualifier of the return type, not of the structure field
+ // as the structure definition is shared between various structures.
+ (yyval.interm.intermTypedNode)->getTypePointer()->setQualifier(EvqConst);
+ }
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(i);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *fields[i]->type(), (yylsp[(3) - (3)]));
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirectStruct, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yylsp[(2) - (3)]));
+ (yyval.interm.intermTypedNode)->setType(*fields[i]->type());
+ }
+ } else {
+ context->error((yylsp[(2) - (3)]), " no such field in structure", (yyvsp[(3) - (3)].lex).string->c_str());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ } else {
+ context->error((yylsp[(2) - (3)]), " field selection requires structure, vector, or matrix on left hand side", (yyvsp[(3) - (3)].lex).string->c_str());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ // don't delete $3.string, it's from the pool
+ }
+ break;
+
+ case 14:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(2) - (2)]), "++", (yyvsp[(1) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostIncrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yylsp[(2) - (2)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yylsp[(2) - (2)]), "++", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 15:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(2) - (2)]), "--", (yyvsp[(1) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostDecrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yylsp[(2) - (2)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yylsp[(2) - (2)]), "--", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 16:
+
+ {
+ if (context->integerErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode), "[]"))
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 17:
+
+ {
+ TFunction* fnCall = (yyvsp[(1) - (1)].interm).function;
+ TOperator op = fnCall->getBuiltInOp();
+
+ if (op != EOpNull)
+ {
+ //
+ // Then this should be a constructor.
+ // Don't go through the symbol table for constructors.
+ // Their parameters will be verified algorithmically.
+ //
+ TType type(EbtVoid, EbpUndefined); // use this to get the type back
+ if (context->constructorErrorCheck((yylsp[(1) - (1)]), (yyvsp[(1) - (1)].interm).intermNode, *fnCall, op, &type)) {
+ (yyval.interm.intermTypedNode) = 0;
+ } else {
+ //
+ // It's a constructor, of type 'type'.
+ //
+ (yyval.interm.intermTypedNode) = context->addConstructor((yyvsp[(1) - (1)].interm).intermNode, &type, op, fnCall, (yylsp[(1) - (1)]));
+ }
+
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator(0, op, (yylsp[(1) - (1)]));
+ }
+ (yyval.interm.intermTypedNode)->setType(type);
+ } else {
+ //
+ // Not a constructor. Find it in the symbol table.
+ //
+ const TFunction* fnCandidate;
+ bool builtIn;
+ fnCandidate = context->findFunction((yylsp[(1) - (1)]), fnCall, &builtIn);
+ if (fnCandidate) {
+ //
+ // A declared function.
+ //
+ if (builtIn && !fnCandidate->getExtension().empty() &&
+ context->extensionErrorCheck((yylsp[(1) - (1)]), fnCandidate->getExtension())) {
+ context->recover();
+ }
+ op = fnCandidate->getBuiltInOp();
+ if (builtIn && op != EOpNull) {
+ //
+ // A function call mapped to a built-in operation.
+ //
+ if (fnCandidate->getParamCount() == 1) {
+ //
+ // Treat it like a built-in unary operator.
+ //
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(op, (yyvsp[(1) - (1)].interm).intermNode, (yylsp[(1) - (1)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ std::stringstream extraInfoStream;
+ extraInfoStream << "built in unary operator function. Type: " << static_cast<TIntermTyped*>((yyvsp[(1) - (1)].interm).intermNode)->getCompleteString();
+ std::string extraInfo = extraInfoStream.str();
+ context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str());
+ YYERROR;
+ }
+ } else {
+ (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, op, (yylsp[(1) - (1)]));
+ }
+ } else {
+ // This is a real function call
+
+ (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, EOpFunctionCall, (yylsp[(1) - (1)]));
+ (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType());
+
+ // this is how we know whether the given function is a builtIn function or a user defined function
+ // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
+ // if builtIn == true, it's definitely a builtIn function with EOpNull
+ if (!builtIn)
+ (yyval.interm.intermTypedNode)->getAsAggregate()->setUserDefined();
+ (yyval.interm.intermTypedNode)->getAsAggregate()->setName(fnCandidate->getMangledName());
+
+ TQualifier qual;
+ for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) {
+ qual = fnCandidate->getParam(i).type->getQualifier();
+ if (qual == EvqOut || qual == EvqInOut) {
+ if (context->lValueErrorCheck((yyval.interm.intermTypedNode)->getLine(), "assign", (yyval.interm.intermTypedNode)->getAsAggregate()->getSequence()[i]->getAsTyped())) {
+ context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error");
+ context->recover();
+ }
+ }
+ }
+ }
+ (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType());
+ } else {
+ // error message was put out by PaFindFunction()
+ // Put on a dummy node for error recovery
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yylsp[(1) - (1)]));
+ context->recover();
+ }
+ }
+ delete fnCall;
+ }
+ break;
+
+ case 18:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (1)].interm);
+ }
+ break;
+
+ case 19:
+
+ {
+ context->error((yylsp[(3) - (3)]), "methods are not supported", "");
+ context->recover();
+ (yyval.interm) = (yyvsp[(3) - (3)].interm);
+ }
+ break;
+
+ case 20:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (2)].interm);
+ }
+ break;
+
+ case 21:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (2)].interm);
+ }
+ break;
+
+ case 22:
+
+ {
+ (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+ (yyval.interm).intermNode = 0;
+ }
+ break;
+
+ case 23:
+
+ {
+ (yyval.interm).function = (yyvsp[(1) - (1)].interm.function);
+ (yyval.interm).intermNode = 0;
+ }
+ break;
+
+ case 24:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[(2) - (2)].interm.intermTypedNode)->getType()) };
+ (yyvsp[(1) - (2)].interm.function)->addParameter(param);
+ (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+ (yyval.interm).intermNode = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ break;
+
+ case 25:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[(3) - (3)].interm.intermTypedNode)->getType()) };
+ (yyvsp[(1) - (3)].interm).function->addParameter(param);
+ (yyval.interm).function = (yyvsp[(1) - (3)].interm).function;
+ (yyval.interm).intermNode = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ }
+ break;
+
+ case 26:
+
+ {
+ (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function);
+ }
+ break;
+
+ case 27:
+
+ {
+ //
+ // Constructor
+ //
+ TOperator op = EOpNull;
+ if ((yyvsp[(1) - (1)].interm.type).userDef) {
+ op = EOpConstructStruct;
+ } else {
+ switch ((yyvsp[(1) - (1)].interm.type).type) {
+ case EbtFloat:
+ if ((yyvsp[(1) - (1)].interm.type).matrix) {
+ switch((yyvsp[(1) - (1)].interm.type).size) {
+ case 2: op = EOpConstructMat2; break;
+ case 3: op = EOpConstructMat3; break;
+ case 4: op = EOpConstructMat4; break;
+ }
+ } else {
+ switch((yyvsp[(1) - (1)].interm.type).size) {
+ case 1: op = EOpConstructFloat; break;
+ case 2: op = EOpConstructVec2; break;
+ case 3: op = EOpConstructVec3; break;
+ case 4: op = EOpConstructVec4; break;
+ }
+ }
+ break;
+ case EbtInt:
+ switch((yyvsp[(1) - (1)].interm.type).size) {
+ case 1: op = EOpConstructInt; break;
+ case 2: op = EOpConstructIVec2; break;
+ case 3: op = EOpConstructIVec3; break;
+ case 4: op = EOpConstructIVec4; break;
+ }
+ break;
+ case EbtBool:
+ switch((yyvsp[(1) - (1)].interm.type).size) {
+ case 1: op = EOpConstructBool; break;
+ case 2: op = EOpConstructBVec2; break;
+ case 3: op = EOpConstructBVec3; break;
+ case 4: op = EOpConstructBVec4; break;
+ }
+ break;
+ default: break;
+ }
+ if (op == EOpNull) {
+ context->error((yylsp[(1) - (1)]), "cannot construct this type", getBasicString((yyvsp[(1) - (1)].interm.type).type));
+ context->recover();
+ (yyvsp[(1) - (1)].interm.type).type = EbtFloat;
+ op = EOpConstructFloat;
+ }
+ }
+ TString tempString;
+ TType type((yyvsp[(1) - (1)].interm.type));
+ TFunction *function = new TFunction(&tempString, type, op);
+ (yyval.interm.function) = function;
+ }
+ break;
+
+ case 28:
+
+ {
+ if (context->reservedErrorCheck((yylsp[(1) - (1)]), *(yyvsp[(1) - (1)].lex).string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction((yyvsp[(1) - (1)].lex).string, type);
+ (yyval.interm.function) = function;
+ }
+ break;
+
+ case 29:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 30:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(1) - (2)]), "++", (yyvsp[(2) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreIncrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yylsp[(1) - (2)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yylsp[(1) - (2)]), "++", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 31:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(1) - (2)]), "--", (yyvsp[(2) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreDecrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yylsp[(1) - (2)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yylsp[(1) - (2)]), "--", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 32:
+
+ {
+ if ((yyvsp[(1) - (2)].interm).op != EOpNull) {
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath((yyvsp[(1) - (2)].interm).op, (yyvsp[(2) - (2)].interm.intermTypedNode), (yylsp[(1) - (2)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ const char* errorOp = "";
+ switch((yyvsp[(1) - (2)].interm).op) {
+ case EOpNegative: errorOp = "-"; break;
+ case EOpLogicalNot: errorOp = "!"; break;
+ default: break;
+ }
+ context->unaryOpError((yylsp[(1) - (2)]), errorOp, (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ } else
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ break;
+
+ case 33:
+
+ { (yyval.interm).op = EOpNull; }
+ break;
+
+ case 34:
+
+ { (yyval.interm).op = EOpNegative; }
+ break;
+
+ case 35:
+
+ { (yyval.interm).op = EOpLogicalNot; }
+ break;
+
+ case 36:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 37:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpMul, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "*", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 38:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpDiv, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "/", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 39:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 40:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpAdd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "+", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 41:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpSub, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "-", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 42:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 43:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 44:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "<", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 45:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), ">", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 46:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "<=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 47:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), ">=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 48:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 49:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "==", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 50:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpNotEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "!=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 51:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 52:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 53:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 54:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 55:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalAnd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "&&", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 56:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 57:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalXor, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "^^", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 58:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 59:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalOr, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]), context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), "||", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yylsp[(2) - (3)]));
+ }
+ }
+ break;
+
+ case 60:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 61:
+
+ {
+ if (context->boolErrorCheck((yylsp[(2) - (5)]), (yyvsp[(1) - (5)].interm.intermTypedNode)))
+ context->recover();
+
+ (yyval.interm.intermTypedNode) = context->intermediate.addSelection((yyvsp[(1) - (5)].interm.intermTypedNode), (yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.intermTypedNode), (yylsp[(2) - (5)]));
+ if ((yyvsp[(3) - (5)].interm.intermTypedNode)->getType() != (yyvsp[(5) - (5)].interm.intermTypedNode)->getType())
+ (yyval.interm.intermTypedNode) = 0;
+
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (5)]), ":", (yyvsp[(3) - (5)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(5) - (5)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(5) - (5)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 62:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 63:
+
+ {
+ if (context->lValueErrorCheck((yylsp[(2) - (3)]), "assign", (yyvsp[(1) - (3)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addAssign((yyvsp[(2) - (3)].interm).op, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->assignError((yylsp[(2) - (3)]), "assign", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 64:
+
+ { (yyval.interm).op = EOpAssign; }
+ break;
+
+ case 65:
+
+ { (yyval.interm).op = EOpMulAssign; }
+ break;
+
+ case 66:
+
+ { (yyval.interm).op = EOpDivAssign; }
+ break;
+
+ case 67:
+
+ { (yyval.interm).op = EOpAddAssign; }
+ break;
+
+ case 68:
+
+ { (yyval.interm).op = EOpSubAssign; }
+ break;
+
+ case 69:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 70:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addComma((yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yylsp[(2) - (3)]));
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yylsp[(2) - (3)]), ",", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(3) - (3)].interm.intermTypedNode);
+ }
+ }
+ break;
+
+ case 71:
+
+ {
+ if (context->constErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 72:
+
+ {
+ TFunction &function = *((yyvsp[(1) - (2)].interm).function);
+
+ TIntermAggregate *prototype = new TIntermAggregate;
+ prototype->setType(function.getReturnType());
+ prototype->setName(function.getName());
+
+ for (size_t i = 0; i < function.getParamCount(); i++)
+ {
+ const TParameter &param = function.getParam(i);
+ if (param.name != 0)
+ {
+ TVariable variable(param.name, *param.type);
+
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), (yylsp[(1) - (2)])), (yylsp[(1) - (2)]));
+ }
+ else
+ {
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, (yylsp[(1) - (2)])), (yylsp[(1) - (2)]));
+ }
+ }
+
+ prototype->setOp(EOpPrototype);
+ (yyval.interm.intermNode) = prototype;
+
+ context->symbolTable.pop();
+ }
+ break;
+
+ case 73:
+
+ {
+ if ((yyvsp[(1) - (2)].interm).intermAggregate)
+ (yyvsp[(1) - (2)].interm).intermAggregate->setOp(EOpDeclaration);
+ (yyval.interm.intermNode) = (yyvsp[(1) - (2)].interm).intermAggregate;
+ }
+ break;
+
+ case 74:
+
+ {
+ if (((yyvsp[(2) - (4)].interm.precision) == EbpHigh) && (context->shaderType == SH_FRAGMENT_SHADER) && !context->fragmentPrecisionHigh) {
+ context->error((yylsp[(1) - (4)]), "precision is not supported in fragment shader", "highp");
+ context->recover();
+ }
+ if (!context->symbolTable.setDefaultPrecision( (yyvsp[(3) - (4)].interm.type), (yyvsp[(2) - (4)].interm.precision) )) {
+ context->error((yylsp[(1) - (4)]), "illegal type argument for default precision qualifier", getBasicString((yyvsp[(3) - (4)].interm.type).type));
+ context->recover();
+ }
+ (yyval.interm.intermNode) = 0;
+ }
+ break;
+
+ case 75:
+
+ {
+ //
+ // Multiple declarations of the same function are allowed.
+ //
+ // If this is a definition, the definition production code will check for redefinitions
+ // (we don't know at this point if it's a definition or not).
+ //
+ // Redeclarations are allowed. But, return types and parameter qualifiers must match.
+ //
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find((yyvsp[(1) - (2)].interm.function)->getMangledName()));
+ if (prevDec) {
+ if (prevDec->getReturnType() != (yyvsp[(1) - (2)].interm.function)->getReturnType()) {
+ context->error((yylsp[(2) - (2)]), "overloaded functions must have the same return type", (yyvsp[(1) - (2)].interm.function)->getReturnType().getBasicString());
+ context->recover();
+ }
+ for (size_t i = 0; i < prevDec->getParamCount(); ++i) {
+ if (prevDec->getParam(i).type->getQualifier() != (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifier()) {
+ context->error((yylsp[(2) - (2)]), "overloaded functions must have the same parameter qualifiers", (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifierString());
+ context->recover();
+ }
+ }
+ }
+
+ //
+ // Check for previously declared variables using the same name.
+ //
+ TSymbol *prevSym = context->symbolTable.find((yyvsp[(1) - (2)].interm.function)->getName());
+ if (prevSym)
+ {
+ if (!prevSym->isFunction())
+ {
+ context->error((yylsp[(2) - (2)]), "redefinition", (yyvsp[(1) - (2)].interm.function)->getName().c_str(), "function");
+ context->recover();
+ }
+ }
+ else
+ {
+ // Insert the unmangled name to detect potential future redefinition as a variable.
+ context->symbolTable.getOuterLevel()->insert((yyvsp[(1) - (2)].interm.function)->getName(), *(yyvsp[(1) - (2)].interm.function));
+ }
+
+ //
+ // If this is a redeclaration, it could also be a definition,
+ // in which case, we want to use the variable names from this one, and not the one that's
+ // being redeclared. So, pass back up this declaration, not the one in the symbol table.
+ //
+ (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+
+ // We're at the inner scope level of the function's arguments and body statement.
+ // Add the function prototype to the surrounding scope instead.
+ context->symbolTable.getOuterLevel()->insert(*(yyval.interm).function);
+ }
+ break;
+
+ case 76:
+
+ {
+ (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function);
+ }
+ break;
+
+ case 77:
+
+ {
+ (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function);
+ }
+ break;
+
+ case 78:
+
+ {
+ // Add the parameter
+ (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function);
+ if ((yyvsp[(2) - (2)].interm).param.type->getBasicType() != EbtVoid)
+ (yyvsp[(1) - (2)].interm.function)->addParameter((yyvsp[(2) - (2)].interm).param);
+ else
+ delete (yyvsp[(2) - (2)].interm).param.type;
+ }
+ break;
+
+ case 79:
+
+ {
+ //
+ // Only first parameter of one-parameter functions can be void
+ // The check for named parameters not being void is done in parameter_declarator
+ //
+ if ((yyvsp[(3) - (3)].interm).param.type->getBasicType() == EbtVoid) {
+ //
+ // This parameter > first is void
+ //
+ context->error((yylsp[(2) - (3)]), "cannot be an argument type except for '(void)'", "void");
+ context->recover();
+ delete (yyvsp[(3) - (3)].interm).param.type;
+ } else {
+ // Add the parameter
+ (yyval.interm.function) = (yyvsp[(1) - (3)].interm.function);
+ (yyvsp[(1) - (3)].interm.function)->addParameter((yyvsp[(3) - (3)].interm).param);
+ }
+ }
+ break;
+
+ case 80:
+
+ {
+ if ((yyvsp[(1) - (3)].interm.type).qualifier != EvqGlobal && (yyvsp[(1) - (3)].interm.type).qualifier != EvqTemporary) {
+ context->error((yylsp[(2) - (3)]), "no qualifiers allowed for function return", getQualifierString((yyvsp[(1) - (3)].interm.type).qualifier));
+ context->recover();
+ }
+ // make sure a sampler is not involved as well...
+ if (context->structQualifierErrorCheck((yylsp[(2) - (3)]), (yyvsp[(1) - (3)].interm.type)))
+ context->recover();
+
+ // Add the function as a prototype after parsing it (we do not support recursion)
+ TFunction *function;
+ TType type((yyvsp[(1) - (3)].interm.type));
+ function = new TFunction((yyvsp[(2) - (3)].lex).string, type);
+ (yyval.interm.function) = function;
+
+ context->symbolTable.push();
+ }
+ break;
+
+ case 81:
+
+ {
+ if ((yyvsp[(1) - (2)].interm.type).type == EbtVoid) {
+ context->error((yylsp[(2) - (2)]), "illegal use of type 'void'", (yyvsp[(2) - (2)].lex).string->c_str());
+ context->recover();
+ }
+ if (context->reservedErrorCheck((yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string))
+ context->recover();
+ TParameter param = {(yyvsp[(2) - (2)].lex).string, new TType((yyvsp[(1) - (2)].interm.type))};
+ (yyval.interm).param = param;
+ }
+ break;
+
+ case 82:
+
+ {
+ // Check that we can make an array out of this type
+ if (context->arrayTypeErrorCheck((yylsp[(3) - (5)]), (yyvsp[(1) - (5)].interm.type)))
+ context->recover();
+
+ if (context->reservedErrorCheck((yylsp[(2) - (5)]), *(yyvsp[(2) - (5)].lex).string))
+ context->recover();
+
+ int size;
+ if (context->arraySizeErrorCheck((yylsp[(3) - (5)]), (yyvsp[(4) - (5)].interm.intermTypedNode), size))
+ context->recover();
+ (yyvsp[(1) - (5)].interm.type).setArray(true, size);
+
+ TType* type = new TType((yyvsp[(1) - (5)].interm.type));
+ TParameter param = { (yyvsp[(2) - (5)].lex).string, type };
+ (yyval.interm).param = param;
+ }
+ break;
+
+ case 83:
+
+ {
+ (yyval.interm) = (yyvsp[(3) - (3)].interm);
+ if (context->paramErrorCheck((yylsp[(3) - (3)]), (yyvsp[(1) - (3)].interm.type).qualifier, (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ }
+ break;
+
+ case 84:
+
+ {
+ (yyval.interm) = (yyvsp[(2) - (2)].interm);
+ if (context->parameterSamplerErrorCheck((yylsp[(2) - (2)]), (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type))
+ context->recover();
+ if (context->paramErrorCheck((yylsp[(2) - (2)]), EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ }
+ break;
+
+ case 85:
+
+ {
+ (yyval.interm) = (yyvsp[(3) - (3)].interm);
+ if (context->paramErrorCheck((yylsp[(3) - (3)]), (yyvsp[(1) - (3)].interm.type).qualifier, (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ }
+ break;
+
+ case 86:
+
+ {
+ (yyval.interm) = (yyvsp[(2) - (2)].interm);
+ if (context->parameterSamplerErrorCheck((yylsp[(2) - (2)]), (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type))
+ context->recover();
+ if (context->paramErrorCheck((yylsp[(2) - (2)]), EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ }
+ break;
+
+ case 87:
+
+ {
+ (yyval.interm.qualifier) = EvqIn;
+ }
+ break;
+
+ case 88:
+
+ {
+ (yyval.interm.qualifier) = EvqIn;
+ }
+ break;
+
+ case 89:
+
+ {
+ (yyval.interm.qualifier) = EvqOut;
+ }
+ break;
+
+ case 90:
+
+ {
+ (yyval.interm.qualifier) = EvqInOut;
+ }
+ break;
+
+ case 91:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[(1) - (1)].interm.type)) };
+ (yyval.interm).param = param;
+ }
+ break;
+
+ case 92:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (1)].interm);
+ }
+ break;
+
+ case 93:
+
+ {
+ if ((yyvsp[(1) - (3)].interm).type.type == EbtInvariant && !(yyvsp[(3) - (3)].lex).symbol)
+ {
+ context->error((yylsp[(3) - (3)]), "undeclared identifier declared as invariant", (yyvsp[(3) - (3)].lex).string->c_str());
+ context->recover();
+ }
+
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(3) - (3)].lex).string, TType((yyvsp[(1) - (3)].interm).type), (yylsp[(3) - (3)]));
+ (yyval.interm).intermAggregate = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, symbol, (yylsp[(3) - (3)]));
+
+ if (context->structQualifierErrorCheck((yylsp[(3) - (3)]), (yyval.interm).type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yylsp[(3) - (3)]), *(yyvsp[(3) - (3)].lex).string, (yyval.interm).type, false))
+ context->recover();
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck((yylsp[(3) - (3)]), *(yyvsp[(3) - (3)].lex).string, (yyval.interm).type, variable))
+ context->recover();
+ if (symbol && variable)
+ symbol->setId(variable->getUniqueId());
+ }
+ break;
+
+ case 94:
+
+ {
+ if (context->structQualifierErrorCheck((yylsp[(3) - (5)]), (yyvsp[(1) - (5)].interm).type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yylsp[(3) - (5)]), *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type, true))
+ context->recover();
+
+ (yyval.interm) = (yyvsp[(1) - (5)].interm);
+
+ if (context->arrayTypeErrorCheck((yylsp[(4) - (5)]), (yyvsp[(1) - (5)].interm).type) || context->arrayQualifierErrorCheck((yylsp[(4) - (5)]), (yyvsp[(1) - (5)].interm).type))
+ context->recover();
+ else {
+ (yyvsp[(1) - (5)].interm).type.setArray(true);
+ TVariable* variable;
+ if (context->arrayErrorCheck((yylsp[(4) - (5)]), *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type, variable))
+ context->recover();
+ }
+ }
+ break;
+
+ case 95:
+
+ {
+ if (context->structQualifierErrorCheck((yylsp[(3) - (6)]), (yyvsp[(1) - (6)].interm).type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yylsp[(3) - (6)]), *(yyvsp[(3) - (6)].lex).string, (yyvsp[(1) - (6)].interm).type, true))
+ context->recover();
+
+ (yyval.interm) = (yyvsp[(1) - (6)].interm);
+
+ if (context->arrayTypeErrorCheck((yylsp[(4) - (6)]), (yyvsp[(1) - (6)].interm).type) || context->arrayQualifierErrorCheck((yylsp[(4) - (6)]), (yyvsp[(1) - (6)].interm).type))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck((yylsp[(4) - (6)]), (yyvsp[(5) - (6)].interm.intermTypedNode), size))
+ context->recover();
+ (yyvsp[(1) - (6)].interm).type.setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck((yylsp[(4) - (6)]), *(yyvsp[(3) - (6)].lex).string, (yyvsp[(1) - (6)].interm).type, variable))
+ context->recover();
+ TType type = TType((yyvsp[(1) - (6)].interm).type);
+ type.setArraySize(size);
+ (yyval.interm).intermAggregate = context->intermediate.growAggregate((yyvsp[(1) - (6)].interm).intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *(yyvsp[(3) - (6)].lex).string, type, (yylsp[(3) - (6)])), (yylsp[(3) - (6)]));
+ }
+ }
+ break;
+
+ case 96:
+
+ {
+ if (context->structQualifierErrorCheck((yylsp[(3) - (5)]), (yyvsp[(1) - (5)].interm).type))
+ context->recover();
+
+ (yyval.interm) = (yyvsp[(1) - (5)].interm);
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer((yylsp[(3) - (5)]), *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type, (yyvsp[(5) - (5)].interm.intermTypedNode), intermNode)) {
+ //
+ // build the intermediate representation
+ //
+ if (intermNode)
+ (yyval.interm).intermAggregate = context->intermediate.growAggregate((yyvsp[(1) - (5)].interm).intermNode, intermNode, (yylsp[(4) - (5)]));
+ else
+ (yyval.interm).intermAggregate = (yyvsp[(1) - (5)].interm).intermAggregate;
+ } else {
+ context->recover();
+ (yyval.interm).intermAggregate = 0;
+ }
+ }
+ break;
+
+ case 97:
+
+ {
+ (yyval.interm).type = (yyvsp[(1) - (1)].interm.type);
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType((yyvsp[(1) - (1)].interm.type)), (yylsp[(1) - (1)])), (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 98:
+
+ {
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (2)].lex).string, TType((yyvsp[(1) - (2)].interm.type)), (yylsp[(2) - (2)]));
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yylsp[(2) - (2)]));
+
+ if (context->structQualifierErrorCheck((yylsp[(2) - (2)]), (yyval.interm).type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string, (yyval.interm).type, false))
+ context->recover();
+
+ (yyval.interm).type = (yyvsp[(1) - (2)].interm.type);
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck((yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string, (yyval.interm).type, variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+ break;
+
+ case 99:
+
+ {
+ context->error((yylsp[(2) - (4)]), "unsized array declarations not supported", (yyvsp[(2) - (4)].lex).string->c_str());
+ context->recover();
+
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (4)].lex).string, TType((yyvsp[(1) - (4)].interm.type)), (yylsp[(2) - (4)]));
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yylsp[(2) - (4)]));
+ (yyval.interm).type = (yyvsp[(1) - (4)].interm.type);
+ }
+ break;
+
+ case 100:
+
+ {
+ TType type = TType((yyvsp[(1) - (5)].interm.type));
+ int size;
+ if (context->arraySizeErrorCheck((yylsp[(2) - (5)]), (yyvsp[(4) - (5)].interm.intermTypedNode), size))
+ context->recover();
+ type.setArraySize(size);
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (5)].lex).string, type, (yylsp[(2) - (5)]));
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yylsp[(2) - (5)]));
+
+ if (context->structQualifierErrorCheck((yylsp[(2) - (5)]), (yyvsp[(1) - (5)].interm.type)))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yylsp[(2) - (5)]), *(yyvsp[(2) - (5)].lex).string, (yyvsp[(1) - (5)].interm.type), true))
+ context->recover();
+
+ (yyval.interm).type = (yyvsp[(1) - (5)].interm.type);
+
+ if (context->arrayTypeErrorCheck((yylsp[(3) - (5)]), (yyvsp[(1) - (5)].interm.type)) || context->arrayQualifierErrorCheck((yylsp[(3) - (5)]), (yyvsp[(1) - (5)].interm.type)))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck((yylsp[(3) - (5)]), (yyvsp[(4) - (5)].interm.intermTypedNode), size))
+ context->recover();
+
+ (yyvsp[(1) - (5)].interm.type).setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck((yylsp[(3) - (5)]), *(yyvsp[(2) - (5)].lex).string, (yyvsp[(1) - (5)].interm.type), variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+ }
+ break;
+
+ case 101:
+
+ {
+ if (context->structQualifierErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+
+ (yyval.interm).type = (yyvsp[(1) - (4)].interm.type);
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer((yylsp[(2) - (4)]), *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), (yyvsp[(4) - (4)].interm.intermTypedNode), intermNode)) {
+ //
+ // Build intermediate representation
+ //
+ if(intermNode)
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(intermNode, (yylsp[(3) - (4)]));
+ else
+ (yyval.interm).intermAggregate = 0;
+ } else {
+ context->recover();
+ (yyval.interm).intermAggregate = 0;
+ }
+ }
+ break;
+
+ case 102:
+
+ {
+ VERTEX_ONLY("invariant declaration", (yylsp[(1) - (2)]));
+ if (context->globalErrorCheck((yylsp[(1) - (2)]), context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ (yyval.interm).type.setBasic(EbtInvariant, EvqInvariantVaryingOut, (yylsp[(2) - (2)]));
+ if (!(yyvsp[(2) - (2)].lex).symbol)
+ {
+ context->error((yylsp[(2) - (2)]), "undeclared identifier declared as invariant", (yyvsp[(2) - (2)].lex).string->c_str());
+ context->recover();
+
+ (yyval.interm).intermAggregate = 0;
+ }
+ else
+ {
+ TIntermSymbol *symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (2)].lex).string, TType((yyval.interm).type), (yylsp[(2) - (2)]));
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yylsp[(2) - (2)]));
+ }
+ }
+ break;
+
+ case 103:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+
+ if ((yyvsp[(1) - (1)].interm.type).array) {
+ context->error((yylsp[(1) - (1)]), "not supported", "first-class array");
+ context->recover();
+ (yyvsp[(1) - (1)].interm.type).setArray(false);
+ }
+ }
+ break;
+
+ case 104:
+
+ {
+ if ((yyvsp[(2) - (2)].interm.type).array) {
+ context->error((yylsp[(2) - (2)]), "not supported", "first-class array");
+ context->recover();
+ (yyvsp[(2) - (2)].interm.type).setArray(false);
+ }
+
+ if ((yyvsp[(1) - (2)].interm.type).qualifier == EvqAttribute &&
+ ((yyvsp[(2) - (2)].interm.type).type == EbtBool || (yyvsp[(2) - (2)].interm.type).type == EbtInt)) {
+ context->error((yylsp[(2) - (2)]), "cannot be bool or int", getQualifierString((yyvsp[(1) - (2)].interm.type).qualifier));
+ context->recover();
+ }
+ if (((yyvsp[(1) - (2)].interm.type).qualifier == EvqVaryingIn || (yyvsp[(1) - (2)].interm.type).qualifier == EvqVaryingOut) &&
+ ((yyvsp[(2) - (2)].interm.type).type == EbtBool || (yyvsp[(2) - (2)].interm.type).type == EbtInt)) {
+ context->error((yylsp[(2) - (2)]), "cannot be bool or int", getQualifierString((yyvsp[(1) - (2)].interm.type).qualifier));
+ context->recover();
+ }
+ (yyval.interm.type) = (yyvsp[(2) - (2)].interm.type);
+ (yyval.interm.type).qualifier = (yyvsp[(1) - (2)].interm.type).qualifier;
+ }
+ break;
+
+ case 105:
+
+ {
+ (yyval.interm.type).setBasic(EbtVoid, EvqConst, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 106:
+
+ {
+ VERTEX_ONLY("attribute", (yylsp[(1) - (1)]));
+ if (context->globalErrorCheck((yylsp[(1) - (1)]), context->symbolTable.atGlobalLevel(), "attribute"))
+ context->recover();
+ (yyval.interm.type).setBasic(EbtVoid, EvqAttribute, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 107:
+
+ {
+ if (context->globalErrorCheck((yylsp[(1) - (1)]), context->symbolTable.atGlobalLevel(), "varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ (yyval.interm.type).setBasic(EbtVoid, EvqVaryingOut, (yylsp[(1) - (1)]));
+ else
+ (yyval.interm.type).setBasic(EbtVoid, EvqVaryingIn, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 108:
+
+ {
+ if (context->globalErrorCheck((yylsp[(1) - (2)]), context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingOut, (yylsp[(1) - (2)]));
+ else
+ (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingIn, (yylsp[(1) - (2)]));
+ }
+ break;
+
+ case 109:
+
+ {
+ if (context->globalErrorCheck((yylsp[(1) - (1)]), context->symbolTable.atGlobalLevel(), "uniform"))
+ context->recover();
+ (yyval.interm.type).setBasic(EbtVoid, EvqUniform, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 110:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+
+ if ((yyval.interm.type).precision == EbpUndefined) {
+ (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[(1) - (1)].interm.type).type);
+ if (context->precisionErrorCheck((yylsp[(1) - (1)]), (yyval.interm.type).precision, (yyvsp[(1) - (1)].interm.type).type)) {
+ context->recover();
+ }
+ }
+ }
+ break;
+
+ case 111:
+
+ {
+ (yyval.interm.type) = (yyvsp[(2) - (2)].interm.type);
+ (yyval.interm.type).precision = (yyvsp[(1) - (2)].interm.precision);
+ }
+ break;
+
+ case 112:
+
+ {
+ (yyval.interm.precision) = EbpHigh;
+ }
+ break;
+
+ case 113:
+
+ {
+ (yyval.interm.precision) = EbpMedium;
+ }
+ break;
+
+ case 114:
+
+ {
+ (yyval.interm.precision) = EbpLow;
+ }
+ break;
+
+ case 115:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+ }
+ break;
+
+ case 116:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (4)].interm.type);
+
+ if (context->arrayTypeErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck((yylsp[(2) - (4)]), (yyvsp[(3) - (4)].interm.intermTypedNode), size))
+ context->recover();
+ (yyval.interm.type).setArray(true, size);
+ }
+ }
+ break;
+
+ case 117:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtVoid, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 118:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 119:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 120:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 121:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(2);
+ }
+ break;
+
+ case 122:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(3);
+ }
+ break;
+
+ case 123:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(4);
+ }
+ break;
+
+ case 124:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(2);
+ }
+ break;
+
+ case 125:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(3);
+ }
+ break;
+
+ case 126:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(4);
+ }
+ break;
+
+ case 127:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(2);
+ }
+ break;
+
+ case 128:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(3);
+ }
+ break;
+
+ case 129:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(4);
+ }
+ break;
+
+ case 130:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(2, true);
+ }
+ break;
+
+ case 131:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(3, true);
+ }
+ break;
+
+ case 132:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).setAggregate(4, true);
+ }
+ break;
+
+ case 133:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSampler2D, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 134:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSamplerCube, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 135:
+
+ {
+ if (!context->supportsExtension("GL_OES_EGL_image_external")) {
+ context->error((yylsp[(1) - (1)]), "unsupported type", "samplerExternalOES");
+ context->recover();
+ }
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSamplerExternalOES, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 136:
+
+ {
+ if (!context->supportsExtension("GL_ARB_texture_rectangle")) {
+ context->error((yylsp[(1) - (1)]), "unsupported type", "sampler2DRect");
+ context->recover();
+ }
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSampler2DRect, qual, (yylsp[(1) - (1)]));
+ }
+ break;
+
+ case 137:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+ (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ }
+ break;
+
+ case 138:
+
+ {
+ //
+ // This is for user defined type names. The lexical phase looked up the
+ // type.
+ //
+ TType& structure = static_cast<TVariable*>((yyvsp[(1) - (1)].lex).symbol)->getType();
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtStruct, qual, (yylsp[(1) - (1)]));
+ (yyval.interm.type).userDef = &structure;
+ }
+ break;
+
+ case 139:
+
+ { if (context->enterStructDeclaration((yylsp[(2) - (3)]), *(yyvsp[(2) - (3)].lex).string)) context->recover(); }
+ break;
+
+ case 140:
+
+ {
+ if (context->reservedErrorCheck((yylsp[(2) - (6)]), *(yyvsp[(2) - (6)].lex).string))
+ context->recover();
+
+ TType* structure = new TType(new TStructure((yyvsp[(2) - (6)].lex).string, (yyvsp[(5) - (6)].interm.fieldList)));
+ TVariable* userTypeDef = new TVariable((yyvsp[(2) - (6)].lex).string, *structure, true);
+ if (! context->symbolTable.insert(*userTypeDef)) {
+ context->error((yylsp[(2) - (6)]), "redefinition", (yyvsp[(2) - (6)].lex).string->c_str(), "struct");
+ context->recover();
+ }
+ (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yylsp[(1) - (6)]));
+ (yyval.interm.type).userDef = structure;
+ context->exitStructDeclaration();
+ }
+ break;
+
+ case 141:
+
+ { if (context->enterStructDeclaration((yylsp[(2) - (2)]), *(yyvsp[(2) - (2)].lex).string)) context->recover(); }
+ break;
+
+ case 142:
+
+ {
+ TType* structure = new TType(new TStructure(NewPoolTString(""), (yyvsp[(4) - (5)].interm.fieldList)));
+ (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yylsp[(1) - (5)]));
+ (yyval.interm.type).userDef = structure;
+ context->exitStructDeclaration();
+ }
+ break;
+
+ case 143:
+
+ {
+ (yyval.interm.fieldList) = (yyvsp[(1) - (1)].interm.fieldList);
+ }
+ break;
+
+ case 144:
+
+ {
+ (yyval.interm.fieldList) = (yyvsp[(1) - (2)].interm.fieldList);
+ for (size_t i = 0; i < (yyvsp[(2) - (2)].interm.fieldList)->size(); ++i) {
+ TField* field = (*(yyvsp[(2) - (2)].interm.fieldList))[i];
+ for (size_t j = 0; j < (yyval.interm.fieldList)->size(); ++j) {
+ if ((*(yyval.interm.fieldList))[j]->name() == field->name()) {
+ context->error((yylsp[(2) - (2)]), "duplicate field name in structure:", "struct", field->name().c_str());
+ context->recover();
+ }
+ }
+ (yyval.interm.fieldList)->push_back(field);
+ }
+ }
+ break;
+
+ case 145:
+
+ {
+ (yyval.interm.fieldList) = (yyvsp[(2) - (3)].interm.fieldList);
+
+ if (context->voidErrorCheck((yylsp[(1) - (3)]), (*(yyvsp[(2) - (3)].interm.fieldList))[0]->name(), (yyvsp[(1) - (3)].interm.type))) {
+ context->recover();
+ }
+ for (unsigned int i = 0; i < (yyval.interm.fieldList)->size(); ++i) {
+ //
+ // Careful not to replace already known aspects of type, like array-ness
+ //
+ TType* type = (*(yyval.interm.fieldList))[i]->type();
+ type->setBasicType((yyvsp[(1) - (3)].interm.type).type);
+ type->setNominalSize((yyvsp[(1) - (3)].interm.type).size);
+ type->setMatrix((yyvsp[(1) - (3)].interm.type).matrix);
+ type->setPrecision((yyvsp[(1) - (3)].interm.type).precision);
+
+ // don't allow arrays of arrays
+ if (type->isArray()) {
+ if (context->arrayTypeErrorCheck((yylsp[(1) - (3)]), (yyvsp[(1) - (3)].interm.type)))
+ context->recover();
+ }
+ if ((yyvsp[(1) - (3)].interm.type).array)
+ type->setArraySize((yyvsp[(1) - (3)].interm.type).arraySize);
+ if ((yyvsp[(1) - (3)].interm.type).userDef)
+ type->setStruct((yyvsp[(1) - (3)].interm.type).userDef->getStruct());
+
+ if (context->structNestingErrorCheck((yylsp[(1) - (3)]), *(*(yyval.interm.fieldList))[i]))
+ context->recover();
+ }
+ }
+ break;
+
+ case 146:
+
+ {
+ (yyval.interm.fieldList) = NewPoolTFieldList();
+ (yyval.interm.fieldList)->push_back((yyvsp[(1) - (1)].interm.field));
+ }
+ break;
+
+ case 147:
+
+ {
+ (yyval.interm.fieldList)->push_back((yyvsp[(3) - (3)].interm.field));
+ }
+ break;
+
+ case 148:
+
+ {
+ if (context->reservedErrorCheck((yylsp[(1) - (1)]), *(yyvsp[(1) - (1)].lex).string))
+ context->recover();
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ (yyval.interm.field) = new TField(type, (yyvsp[(1) - (1)].lex).string);
+ }
+ break;
+
+ case 149:
+
+ {
+ if (context->reservedErrorCheck((yylsp[(1) - (4)]), *(yyvsp[(1) - (4)].lex).string))
+ context->recover();
+
+ TType* type = new TType(EbtVoid, EbpUndefined);
+ int size = 0;
+ if (context->arraySizeErrorCheck((yylsp[(3) - (4)]), (yyvsp[(3) - (4)].interm.intermTypedNode), size))
+ context->recover();
+ type->setArraySize(size);
+
+ (yyval.interm.field) = new TField(type, (yyvsp[(1) - (4)].lex).string);
+ }
+ break;
+
+ case 150:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); }
+ break;
+
+ case 151:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 152:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermAggregate); }
+ break;
+
+ case 153:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 154:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 155:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 156:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 157:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 158:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 159:
+
+ { (yyval.interm.intermAggregate) = 0; }
+ break;
+
+ case 160:
+
+ { context->symbolTable.push(); }
+ break;
+
+ case 161:
+
+ { context->symbolTable.pop(); }
+ break;
+
+ case 162:
+
+ {
+ if ((yyvsp[(3) - (5)].interm.intermAggregate) != 0) {
+ (yyvsp[(3) - (5)].interm.intermAggregate)->setOp(EOpSequence);
+ (yyvsp[(3) - (5)].interm.intermAggregate)->setLine((yyloc));
+ }
+ (yyval.interm.intermAggregate) = (yyvsp[(3) - (5)].interm.intermAggregate);
+ }
+ break;
+
+ case 163:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 164:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); }
+ break;
+
+ case 165:
+
+ { context->symbolTable.push(); }
+ break;
+
+ case 166:
+
+ { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode); }
+ break;
+
+ case 167:
+
+ { context->symbolTable.push(); }
+ break;
+
+ case 168:
+
+ { context->symbolTable.pop(); (yyval.interm.intermNode) = (yyvsp[(2) - (2)].interm.intermNode); }
+ break;
+
+ case 169:
+
+ {
+ (yyval.interm.intermNode) = 0;
+ }
+ break;
+
+ case 170:
+
+ {
+ if ((yyvsp[(2) - (3)].interm.intermAggregate)) {
+ (yyvsp[(2) - (3)].interm.intermAggregate)->setOp(EOpSequence);
+ (yyvsp[(2) - (3)].interm.intermAggregate)->setLine((yyloc));
+ }
+ (yyval.interm.intermNode) = (yyvsp[(2) - (3)].interm.intermAggregate);
+ }
+ break;
+
+ case 171:
+
+ {
+ (yyval.interm.intermAggregate) = context->intermediate.makeAggregate((yyvsp[(1) - (1)].interm.intermNode), (yyloc));
+ }
+ break;
+
+ case 172:
+
+ {
+ (yyval.interm.intermAggregate) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermAggregate), (yyvsp[(2) - (2)].interm.intermNode), (yyloc));
+ }
+ break;
+
+ case 173:
+
+ { (yyval.interm.intermNode) = 0; }
+ break;
+
+ case 174:
+
+ { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[(1) - (2)].interm.intermTypedNode)); }
+ break;
+
+ case 175:
+
+ {
+ if (context->boolErrorCheck((yylsp[(1) - (5)]), (yyvsp[(3) - (5)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermNode) = context->intermediate.addSelection((yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.nodePair), (yylsp[(1) - (5)]));
+ }
+ break;
+
+ case 176:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermNode);
+ }
+ break;
+
+ case 177:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (1)].interm.intermNode);
+ (yyval.interm.nodePair).node2 = 0;
+ }
+ break;
+
+ case 178:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ if (context->boolErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode)->getLine(), (yyvsp[(1) - (1)].interm.intermTypedNode)))
+ context->recover();
+ }
+ break;
+
+ case 179:
+
+ {
+ TIntermNode* intermNode;
+ if (context->structQualifierErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+ if (context->boolErrorCheck((yylsp[(2) - (4)]), (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+
+ if (!context->executeInitializer((yylsp[(2) - (4)]), *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), (yyvsp[(4) - (4)].interm.intermTypedNode), intermNode))
+ (yyval.interm.intermTypedNode) = (yyvsp[(4) - (4)].interm.intermTypedNode);
+ else {
+ context->recover();
+ (yyval.interm.intermTypedNode) = 0;
+ }
+ }
+ break;
+
+ case 180:
+
+ { context->symbolTable.push(); ++context->loopNestingLevel; }
+ break;
+
+ case 181:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[(4) - (6)].interm.intermTypedNode), 0, (yyvsp[(6) - (6)].interm.intermNode), (yylsp[(1) - (6)]));
+ --context->loopNestingLevel;
+ }
+ break;
+
+ case 182:
+
+ { ++context->loopNestingLevel; }
+ break;
+
+ case 183:
+
+ {
+ if (context->boolErrorCheck((yylsp[(8) - (8)]), (yyvsp[(6) - (8)].interm.intermTypedNode)))
+ context->recover();
+
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[(6) - (8)].interm.intermTypedNode), 0, (yyvsp[(3) - (8)].interm.intermNode), (yylsp[(4) - (8)]));
+ --context->loopNestingLevel;
+ }
+ break;
+
+ case 184:
+
+ { context->symbolTable.push(); ++context->loopNestingLevel; }
+ break;
+
+ case 185:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[(4) - (7)].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node2), (yyvsp[(7) - (7)].interm.intermNode), (yylsp[(1) - (7)]));
+ --context->loopNestingLevel;
+ }
+ break;
+
+ case 186:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ }
+ break;
+
+ case 187:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ }
+ break;
+
+ case 188:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ }
+ break;
+
+ case 189:
+
+ {
+ (yyval.interm.intermTypedNode) = 0;
+ }
+ break;
+
+ case 190:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (2)].interm.intermTypedNode);
+ (yyval.interm.nodePair).node2 = 0;
+ }
+ break;
+
+ case 191:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermTypedNode);
+ }
+ break;
+
+ case 192:
+
+ {
+ if (context->loopNestingLevel <= 0) {
+ context->error((yylsp[(1) - (2)]), "continue statement only allowed in loops", "");
+ context->recover();
+ }
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpContinue, (yylsp[(1) - (2)]));
+ }
+ break;
+
+ case 193:
+
+ {
+ if (context->loopNestingLevel <= 0) {
+ context->error((yylsp[(1) - (2)]), "break statement only allowed in loops", "");
+ context->recover();
+ }
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpBreak, (yylsp[(1) - (2)]));
+ }
+ break;
+
+ case 194:
+
+ {
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yylsp[(1) - (2)]));
+ if (context->currentFunctionType->getBasicType() != EbtVoid) {
+ context->error((yylsp[(1) - (2)]), "non-void function must return a value", "return");
+ context->recover();
+ }
+ }
+ break;
+
+ case 195:
+
+ {
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[(2) - (3)].interm.intermTypedNode), (yylsp[(1) - (3)]));
+ context->functionReturnsValue = true;
+ if (context->currentFunctionType->getBasicType() == EbtVoid) {
+ context->error((yylsp[(1) - (3)]), "void function cannot return a value", "return");
+ context->recover();
+ } else if (*(context->currentFunctionType) != (yyvsp[(2) - (3)].interm.intermTypedNode)->getType()) {
+ context->error((yylsp[(1) - (3)]), "function return is not matching type:", "return");
+ context->recover();
+ }
+ }
+ break;
+
+ case 196:
+
+ {
+ FRAG_ONLY("discard", (yylsp[(1) - (2)]));
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpKill, (yylsp[(1) - (2)]));
+ }
+ break;
+
+ case 197:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ context->treeRoot = (yyval.interm.intermNode);
+ }
+ break;
+
+ case 198:
+
+ {
+ (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermNode), (yyvsp[(2) - (2)].interm.intermNode), (yyloc));
+ context->treeRoot = (yyval.interm.intermNode);
+ }
+ break;
+
+ case 199:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ }
+ break;
+
+ case 200:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ }
+ break;
+
+ case 201:
+
+ {
+ TFunction* function = (yyvsp[(1) - (1)].interm).function;
+
+ const TSymbol *builtIn = context->symbolTable.findBuiltIn(function->getMangledName());
+
+ if (builtIn)
+ {
+ context->error((yylsp[(1) - (1)]), "built-in functions cannot be redefined", function->getName().c_str());
+ context->recover();
+ }
+
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName()));
+ //
+ // Note: 'prevDec' could be 'function' if this is the first time we've seen function
+ // as it would have just been put in the symbol table. Otherwise, we're looking up
+ // an earlier occurance.
+ //
+ if (prevDec->isDefined()) {
+ //
+ // Then this function already has a body.
+ //
+ context->error((yylsp[(1) - (1)]), "function already has a body", function->getName().c_str());
+ context->recover();
+ }
+ prevDec->setDefined();
+
+ //
+ // Raise error message if main function takes any parameters or return anything other than void
+ //
+ if (function->getName() == "main") {
+ if (function->getParamCount() > 0) {
+ context->error((yylsp[(1) - (1)]), "function cannot take any parameter(s)", function->getName().c_str());
+ context->recover();
+ }
+ if (function->getReturnType().getBasicType() != EbtVoid) {
+ context->error((yylsp[(1) - (1)]), "", function->getReturnType().getBasicString(), "main function cannot return a value");
+ context->recover();
+ }
+ }
+
+ //
+ // Remember the return type for later checking for RETURN statements.
+ //
+ context->currentFunctionType = &(prevDec->getReturnType());
+ context->functionReturnsValue = false;
+
+ //
+ // Insert parameters into the symbol table.
+ // If the parameter has no name, it's not an error, just don't insert it
+ // (could be used for unused args).
+ //
+ // Also, accumulate the list of parameters into the HIL, so lower level code
+ // knows where to find parameters.
+ //
+ TIntermAggregate* paramNodes = new TIntermAggregate;
+ for (size_t i = 0; i < function->getParamCount(); i++) {
+ const TParameter& param = function->getParam(i);
+ if (param.name != 0) {
+ TVariable *variable = new TVariable(param.name, *param.type);
+ //
+ // Insert the parameters with name in the symbol table.
+ //
+ if (! context->symbolTable.insert(*variable)) {
+ context->error((yylsp[(1) - (1)]), "redefinition", variable->getName().c_str());
+ context->recover();
+ delete variable;
+ }
+
+ //
+ // Add the parameter to the HIL
+ //
+ paramNodes = context->intermediate.growAggregate(
+ paramNodes,
+ context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(),
+ (yylsp[(1) - (1)])),
+ (yylsp[(1) - (1)]));
+ } else {
+ paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, (yylsp[(1) - (1)])), (yylsp[(1) - (1)]));
+ }
+ }
+ context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yylsp[(1) - (1)]));
+ (yyvsp[(1) - (1)].interm).intermAggregate = paramNodes;
+ context->loopNestingLevel = 0;
+ }
+ break;
+
+ case 202:
+
+ {
+ //?? Check that all paths return a value if return type != void ?
+ // May be best done as post process phase on intermediate code
+ if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+ context->error((yylsp[(1) - (3)]), "function does not return a value:", "", (yyvsp[(1) - (3)].interm).function->getName().c_str());
+ context->recover();
+ }
+
+ (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermAggregate, (yyvsp[(3) - (3)].interm.intermNode), (yyloc));
+ context->intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yylsp[(1) - (3)]));
+ (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[(1) - (3)].interm).function->getMangledName().c_str());
+ (yyval.interm.intermNode)->getAsAggregate()->setType((yyvsp[(1) - (3)].interm).function->getReturnType());
+
+ // store the pragma information for debug and optimize and other vendor specific
+ // information. This information can be queried from the parse tree
+ (yyval.interm.intermNode)->getAsAggregate()->setOptimize(context->pragma().optimize);
+ (yyval.interm.intermNode)->getAsAggregate()->setDebug(context->pragma().debug);
+
+ context->symbolTable.pop();
+ }
+ break;
+
+
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (&yylloc, context, YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (&yylloc, context, yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+ yyerror_range[1] = yylloc;
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, &yylloc, context);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ yyerror_range[1] = yylsp[1-yylen];
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ yyerror_range[1] = *yylsp;
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, yylsp, context);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ yyerror_range[2] = yylloc;
+ /* Using YYLLOC is tempting, but would change the location of
+ the lookahead. YYLOC is available though. */
+ YYLLOC_DEFAULT (yyloc, yyerror_range, 2);
+ *++yylsp = yyloc;
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (&yylloc, context, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc, context);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, yylsp, context);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+
+
+void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason) {
+ context->error(*yylloc, reason, "");
+ context->recover();
+}
+
+int glslang_parse(TParseContext* context) {
+ return yyparse(context);
+}
diff --git a/src/compiler/glslang_tab.h b/src/compiler/glslang_tab.h
new file mode 100644
index 00000000..2f0f1106
--- /dev/null
+++ b/src/compiler/glslang_tab.h
@@ -0,0 +1,222 @@
+/* A Bison parser, made by GNU Bison 2.7. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_YY_GLSLANG_TAB_H_INCLUDED
+# define YY_YY_GLSLANG_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+/* "%code requires" blocks. */
+
+
+#define YYLTYPE TSourceLoc
+#define YYLTYPE_IS_DECLARED 1
+
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INVARIANT = 258,
+ HIGH_PRECISION = 259,
+ MEDIUM_PRECISION = 260,
+ LOW_PRECISION = 261,
+ PRECISION = 262,
+ ATTRIBUTE = 263,
+ CONST_QUAL = 264,
+ BOOL_TYPE = 265,
+ FLOAT_TYPE = 266,
+ INT_TYPE = 267,
+ BREAK = 268,
+ CONTINUE = 269,
+ DO = 270,
+ ELSE = 271,
+ FOR = 272,
+ IF = 273,
+ DISCARD = 274,
+ RETURN = 275,
+ BVEC2 = 276,
+ BVEC3 = 277,
+ BVEC4 = 278,
+ IVEC2 = 279,
+ IVEC3 = 280,
+ IVEC4 = 281,
+ VEC2 = 282,
+ VEC3 = 283,
+ VEC4 = 284,
+ MATRIX2 = 285,
+ MATRIX3 = 286,
+ MATRIX4 = 287,
+ IN_QUAL = 288,
+ OUT_QUAL = 289,
+ INOUT_QUAL = 290,
+ UNIFORM = 291,
+ VARYING = 292,
+ STRUCT = 293,
+ VOID_TYPE = 294,
+ WHILE = 295,
+ SAMPLER2D = 296,
+ SAMPLERCUBE = 297,
+ SAMPLER_EXTERNAL_OES = 298,
+ SAMPLER2DRECT = 299,
+ IDENTIFIER = 300,
+ TYPE_NAME = 301,
+ FLOATCONSTANT = 302,
+ INTCONSTANT = 303,
+ BOOLCONSTANT = 304,
+ LEFT_OP = 305,
+ RIGHT_OP = 306,
+ INC_OP = 307,
+ DEC_OP = 308,
+ LE_OP = 309,
+ GE_OP = 310,
+ EQ_OP = 311,
+ NE_OP = 312,
+ AND_OP = 313,
+ OR_OP = 314,
+ XOR_OP = 315,
+ MUL_ASSIGN = 316,
+ DIV_ASSIGN = 317,
+ ADD_ASSIGN = 318,
+ MOD_ASSIGN = 319,
+ LEFT_ASSIGN = 320,
+ RIGHT_ASSIGN = 321,
+ AND_ASSIGN = 322,
+ XOR_ASSIGN = 323,
+ OR_ASSIGN = 324,
+ SUB_ASSIGN = 325,
+ LEFT_PAREN = 326,
+ RIGHT_PAREN = 327,
+ LEFT_BRACKET = 328,
+ RIGHT_BRACKET = 329,
+ LEFT_BRACE = 330,
+ RIGHT_BRACE = 331,
+ DOT = 332,
+ COMMA = 333,
+ COLON = 334,
+ EQUAL = 335,
+ SEMICOLON = 336,
+ BANG = 337,
+ DASH = 338,
+ TILDE = 339,
+ PLUS = 340,
+ STAR = 341,
+ SLASH = 342,
+ PERCENT = 343,
+ LEFT_ANGLE = 344,
+ RIGHT_ANGLE = 345,
+ VERTICAL_BAR = 346,
+ CARET = 347,
+ AMPERSAND = 348,
+ QUESTION = 349
+ };
+#endif
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+
+ struct {
+ union {
+ TString *string;
+ float f;
+ int i;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TField* field;
+ TFieldList* fieldList;
+ };
+ } interm;
+
+
+
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+} YYLTYPE;
+# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (TParseContext* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_YY_GLSLANG_TAB_H_INCLUDED */
diff --git a/src/compiler/intermOut.cpp b/src/compiler/intermOut.cpp
new file mode 100644
index 00000000..13aa96af
--- /dev/null
+++ b/src/compiler/intermOut.cpp
@@ -0,0 +1,424 @@
+//
+// 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.
+//
+
+#include "compiler/localintermediate.h"
+
+//
+// Two purposes:
+// 1. Show an example of how to iterate tree. Functions can
+// also directly call Traverse() on children themselves to
+// have finer grained control over the process than shown here.
+// See the last function for how to get started.
+// 2. Print out a text based description of the tree.
+//
+
+//
+// Use this class to carry along data from node to node in
+// the traversal
+//
+class TOutputTraverser : public TIntermTraverser {
+public:
+ TOutputTraverser(TInfoSinkBase& i) : sink(i) { }
+ TInfoSinkBase& sink;
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+};
+
+TString TType::getCompleteString() const
+{
+ TStringStream stream;
+
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+ stream << getQualifierString() << " " << getPrecisionString() << " ";
+ if (array)
+ stream << "array[" << getArraySize() << "] of ";
+ if (matrix)
+ stream << size << "X" << size << " matrix of ";
+ else if (size > 1)
+ stream << size << "-component vector of ";
+
+ stream << getBasicString();
+ return stream.str();
+}
+
+//
+// Helper functions for printing, not part of traversing.
+//
+
+void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth)
+{
+ int i;
+
+ sink.location(node->getLine());
+
+ for (i = 0; i < depth; ++i)
+ sink << " ";
+}
+
+//
+// The rest of the file are the traversal functions. The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. If you process children yourself,
+// return false.
+//
+
+void TOutputTraverser::visitSymbol(TIntermSymbol* node)
+{
+ OutputTreeText(sink, node, depth);
+
+ sink << "'" << node->getSymbol() << "' ";
+ sink << "(" << node->getCompleteString() << ")\n";
+}
+
+bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpAssign: out << "move second child to first child"; break;
+ case EOpInitialize: out << "initialize first child with second child"; break;
+ case EOpAddAssign: out << "add second child into first child"; break;
+ case EOpSubAssign: out << "subtract second child into first child"; break;
+ case EOpMulAssign: out << "multiply second child into first child"; break;
+ case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break;
+ case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break;
+ case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break;
+ case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break;
+ case EOpDivAssign: out << "divide second child into first child"; break;
+ case EOpIndexDirect: out << "direct index"; break;
+ case EOpIndexIndirect: out << "indirect index"; break;
+ case EOpIndexDirectStruct: out << "direct index for structure"; break;
+ case EOpVectorSwizzle: out << "vector swizzle"; break;
+
+ case EOpAdd: out << "add"; break;
+ case EOpSub: out << "subtract"; break;
+ case EOpMul: out << "component-wise multiply"; break;
+ case EOpDiv: out << "divide"; break;
+ case EOpEqual: out << "Compare Equal"; break;
+ case EOpNotEqual: out << "Compare Not Equal"; break;
+ case EOpLessThan: out << "Compare Less Than"; break;
+ case EOpGreaterThan: out << "Compare Greater Than"; break;
+ case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
+ case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
+
+ case EOpVectorTimesScalar: out << "vector-scale"; break;
+ case EOpVectorTimesMatrix: out << "vector-times-matrix"; break;
+ case EOpMatrixTimesVector: out << "matrix-times-vector"; break;
+ case EOpMatrixTimesScalar: out << "matrix-scale"; break;
+ case EOpMatrixTimesMatrix: out << "matrix-multiply"; break;
+
+ case EOpLogicalOr: out << "logical-or"; break;
+ case EOpLogicalXor: out << "logical-xor"; break;
+ case EOpLogicalAnd: out << "logical-and"; break;
+ default: out << "<unknown op>";
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpNegative: out << "Negate value"; break;
+ case EOpVectorLogicalNot:
+ case EOpLogicalNot: out << "Negate conditional"; break;
+
+ case EOpPostIncrement: out << "Post-Increment"; break;
+ case EOpPostDecrement: out << "Post-Decrement"; break;
+ case EOpPreIncrement: out << "Pre-Increment"; break;
+ case EOpPreDecrement: out << "Pre-Decrement"; break;
+
+ case EOpConvIntToBool: out << "Convert int to bool"; break;
+ case EOpConvFloatToBool:out << "Convert float to bool";break;
+ case EOpConvBoolToFloat:out << "Convert bool to float";break;
+ case EOpConvIntToFloat: out << "Convert int to float"; break;
+ case EOpConvFloatToInt: out << "Convert float to int"; break;
+ case EOpConvBoolToInt: out << "Convert bool to int"; break;
+
+ case EOpRadians: out << "radians"; break;
+ case EOpDegrees: out << "degrees"; break;
+ case EOpSin: out << "sine"; break;
+ case EOpCos: out << "cosine"; break;
+ case EOpTan: out << "tangent"; break;
+ case EOpAsin: out << "arc sine"; break;
+ case EOpAcos: out << "arc cosine"; break;
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpExp: out << "exp"; break;
+ case EOpLog: out << "log"; break;
+ case EOpExp2: out << "exp2"; break;
+ case EOpLog2: out << "log2"; break;
+ case EOpSqrt: out << "sqrt"; break;
+ case EOpInverseSqrt: out << "inverse sqrt"; break;
+
+ case EOpAbs: out << "Absolute value"; break;
+ case EOpSign: out << "Sign"; break;
+ case EOpFloor: out << "Floor"; break;
+ case EOpCeil: out << "Ceiling"; break;
+ case EOpFract: out << "Fraction"; break;
+
+ case EOpLength: out << "length"; break;
+ case EOpNormalize: out << "normalize"; break;
+ // case EOpDPdx: out << "dPdx"; break;
+ // case EOpDPdy: out << "dPdy"; break;
+ // case EOpFwidth: out << "fwidth"; break;
+
+ case EOpAny: out << "any"; break;
+ case EOpAll: out << "all"; break;
+
+ default:
+ out.prefix(EPrefixError);
+ out << "Bad unary op";
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ TInfoSinkBase& out = sink;
+
+ if (node->getOp() == EOpNull) {
+ out.prefix(EPrefixError);
+ out << "node is still EOpNull!";
+ return true;
+ }
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpSequence: out << "Sequence\n"; return true;
+ case EOpComma: out << "Comma\n"; return true;
+ case EOpFunction: out << "Function Definition: " << node->getName(); break;
+ case EOpFunctionCall: out << "Function Call: " << node->getName(); break;
+ case EOpParameters: out << "Function Parameters: "; break;
+
+ case EOpConstructFloat: out << "Construct float"; break;
+ case EOpConstructVec2: out << "Construct vec2"; break;
+ case EOpConstructVec3: out << "Construct vec3"; break;
+ case EOpConstructVec4: out << "Construct vec4"; break;
+ case EOpConstructBool: out << "Construct bool"; break;
+ case EOpConstructBVec2: out << "Construct bvec2"; break;
+ case EOpConstructBVec3: out << "Construct bvec3"; break;
+ case EOpConstructBVec4: out << "Construct bvec4"; break;
+ case EOpConstructInt: out << "Construct int"; break;
+ case EOpConstructIVec2: out << "Construct ivec2"; break;
+ case EOpConstructIVec3: out << "Construct ivec3"; break;
+ case EOpConstructIVec4: out << "Construct ivec4"; break;
+ case EOpConstructMat2: out << "Construct mat2"; break;
+ case EOpConstructMat3: out << "Construct mat3"; break;
+ case EOpConstructMat4: out << "Construct mat4"; break;
+ case EOpConstructStruct: out << "Construct structure"; break;
+
+ case EOpLessThan: out << "Compare Less Than"; break;
+ case EOpGreaterThan: out << "Compare Greater Than"; break;
+ case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
+ case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
+ case EOpVectorEqual: out << "Equal"; break;
+ case EOpVectorNotEqual: out << "NotEqual"; break;
+
+ case EOpMod: out << "mod"; break;
+ case EOpPow: out << "pow"; break;
+
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpMin: out << "min"; break;
+ case EOpMax: out << "max"; break;
+ case EOpClamp: out << "clamp"; break;
+ case EOpMix: out << "mix"; break;
+ case EOpStep: out << "step"; break;
+ case EOpSmoothStep: out << "smoothstep"; break;
+
+ case EOpDistance: out << "distance"; break;
+ case EOpDot: out << "dot-product"; break;
+ case EOpCross: out << "cross-product"; break;
+ case EOpFaceForward: out << "face-forward"; break;
+ case EOpReflect: out << "reflect"; break;
+ case EOpRefract: out << "refract"; break;
+ case EOpMul: out << "component-wise multiply"; break;
+
+ case EOpDeclaration: out << "Declaration: "; break;
+
+ default:
+ out.prefix(EPrefixError);
+ out << "Bad aggregation op";
+ }
+
+ if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ out << "Test condition and select";
+ out << " (" << node->getCompleteString() << ")\n";
+
+ ++depth;
+
+ OutputTreeText(sink, node, depth);
+ out << "Condition\n";
+ node->getCondition()->traverse(this);
+
+ OutputTreeText(sink, node, depth);
+ if (node->getTrueBlock()) {
+ out << "true case\n";
+ node->getTrueBlock()->traverse(this);
+ } else
+ out << "true case is null\n";
+
+ if (node->getFalseBlock()) {
+ OutputTreeText(sink, node, depth);
+ out << "false case\n";
+ node->getFalseBlock()->traverse(this);
+ }
+
+ --depth;
+
+ return false;
+}
+
+void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+ TInfoSinkBase& out = sink;
+
+ size_t size = node->getType().getObjectSize();
+
+ for (size_t i = 0; i < size; i++) {
+ OutputTreeText(out, node, depth);
+ switch (node->getUnionArrayPointer()[i].getType()) {
+ case EbtBool:
+ if (node->getUnionArrayPointer()[i].getBConst())
+ out << "true";
+ else
+ out << "false";
+
+ out << " (" << "const bool" << ")";
+ out << "\n";
+ break;
+ case EbtFloat:
+ out << node->getUnionArrayPointer()[i].getFConst();
+ out << " (const float)\n";
+ break;
+ case EbtInt:
+ out << node->getUnionArrayPointer()[i].getIConst();
+ out << " (const int)\n";
+ break;
+ default:
+ out.message(EPrefixInternalError, node->getLine(), "Unknown constant");
+ break;
+ }
+ }
+}
+
+bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ out << "Loop with condition ";
+ if (node->getType() == ELoopDoWhile)
+ out << "not ";
+ out << "tested first\n";
+
+ ++depth;
+
+ OutputTreeText(sink, node, depth);
+ if (node->getCondition()) {
+ out << "Loop Condition\n";
+ node->getCondition()->traverse(this);
+ } else
+ out << "No loop condition\n";
+
+ OutputTreeText(sink, node, depth);
+ if (node->getBody()) {
+ out << "Loop Body\n";
+ node->getBody()->traverse(this);
+ } else
+ out << "No loop body\n";
+
+ if (node->getExpression()) {
+ OutputTreeText(sink, node, depth);
+ out << "Loop Terminal Expression\n";
+ node->getExpression()->traverse(this);
+ }
+
+ --depth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getFlowOp()) {
+ case EOpKill: out << "Branch: Kill"; break;
+ case EOpBreak: out << "Branch: Break"; break;
+ case EOpContinue: out << "Branch: Continue"; break;
+ case EOpReturn: out << "Branch: Return"; break;
+ default: out << "Branch: Unknown Branch"; break;
+ }
+
+ if (node->getExpression()) {
+ out << " with expression\n";
+ ++depth;
+ node->getExpression()->traverse(this);
+ --depth;
+ } else
+ out << "\n";
+
+ return false;
+}
+
+//
+// This function is the one to call externally to start the traversal.
+// Individual functions can be initialized to 0 to skip processing of that
+// type of node. It's children will still be processed.
+//
+void TIntermediate::outputTree(TIntermNode* root)
+{
+ if (root == 0)
+ return;
+
+ TOutputTraverser it(infoSink.info);
+
+ root->traverse(&it);
+}
diff --git a/src/compiler/intermediate.h b/src/compiler/intermediate.h
new file mode 100644
index 00000000..738621fe
--- /dev/null
+++ b/src/compiler/intermediate.h
@@ -0,0 +1,579 @@
+//
+// 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.
+//
+
+//
+// Definition of the in-memory high-level intermediate representation
+// of shaders. This is a tree that parser creates.
+//
+// Nodes in the tree are defined as a hierarchy of classes derived from
+// TIntermNode. Each is a node in a tree. There is no preset branching factor;
+// each node can have it's own type of list of children.
+//
+
+#ifndef __INTERMEDIATE_H
+#define __INTERMEDIATE_H
+
+#include "GLSLANG/ShaderLang.h"
+
+#include <algorithm>
+#include "compiler/Common.h"
+#include "compiler/Types.h"
+#include "compiler/ConstantUnion.h"
+
+//
+// Operators used by the high-level (parse tree) representation.
+//
+enum TOperator {
+ EOpNull, // if in a node, should only mean a node is still being built
+ EOpSequence, // denotes a list of statements, or parameters, etc.
+ EOpFunctionCall,
+ EOpFunction, // For function definition
+ EOpParameters, // an aggregate listing the parameters to a function
+
+ EOpDeclaration,
+ EOpPrototype,
+
+ //
+ // Unary operators
+ //
+
+ EOpNegative,
+ EOpLogicalNot,
+ EOpVectorLogicalNot,
+
+ EOpPostIncrement,
+ EOpPostDecrement,
+ EOpPreIncrement,
+ EOpPreDecrement,
+
+ EOpConvIntToBool,
+ EOpConvFloatToBool,
+ EOpConvBoolToFloat,
+ EOpConvIntToFloat,
+ EOpConvFloatToInt,
+ EOpConvBoolToInt,
+
+ //
+ // binary operations
+ //
+
+ EOpAdd,
+ EOpSub,
+ EOpMul,
+ EOpDiv,
+ EOpEqual,
+ EOpNotEqual,
+ EOpVectorEqual,
+ EOpVectorNotEqual,
+ EOpLessThan,
+ EOpGreaterThan,
+ EOpLessThanEqual,
+ EOpGreaterThanEqual,
+ EOpComma,
+
+ EOpVectorTimesScalar,
+ EOpVectorTimesMatrix,
+ EOpMatrixTimesVector,
+ EOpMatrixTimesScalar,
+
+ EOpLogicalOr,
+ EOpLogicalXor,
+ EOpLogicalAnd,
+
+ EOpIndexDirect,
+ EOpIndexIndirect,
+ EOpIndexDirectStruct,
+
+ EOpVectorSwizzle,
+
+ //
+ // Built-in functions potentially mapped to operators
+ //
+
+ EOpRadians,
+ EOpDegrees,
+ EOpSin,
+ EOpCos,
+ EOpTan,
+ EOpAsin,
+ EOpAcos,
+ EOpAtan,
+
+ EOpPow,
+ EOpExp,
+ EOpLog,
+ EOpExp2,
+ EOpLog2,
+ EOpSqrt,
+ EOpInverseSqrt,
+
+ EOpAbs,
+ EOpSign,
+ EOpFloor,
+ EOpCeil,
+ EOpFract,
+ EOpMod,
+ EOpMin,
+ EOpMax,
+ EOpClamp,
+ EOpMix,
+ EOpStep,
+ EOpSmoothStep,
+
+ EOpLength,
+ EOpDistance,
+ EOpDot,
+ EOpCross,
+ EOpNormalize,
+ EOpFaceForward,
+ EOpReflect,
+ EOpRefract,
+
+ EOpDFdx, // Fragment only, OES_standard_derivatives extension
+ EOpDFdy, // Fragment only, OES_standard_derivatives extension
+ EOpFwidth, // Fragment only, OES_standard_derivatives extension
+
+ EOpMatrixTimesMatrix,
+
+ EOpAny,
+ EOpAll,
+
+ //
+ // Branch
+ //
+
+ EOpKill, // Fragment only
+ EOpReturn,
+ EOpBreak,
+ EOpContinue,
+
+ //
+ // Constructors
+ //
+
+ EOpConstructInt,
+ EOpConstructBool,
+ EOpConstructFloat,
+ EOpConstructVec2,
+ EOpConstructVec3,
+ EOpConstructVec4,
+ EOpConstructBVec2,
+ EOpConstructBVec3,
+ EOpConstructBVec4,
+ EOpConstructIVec2,
+ EOpConstructIVec3,
+ EOpConstructIVec4,
+ EOpConstructMat2,
+ EOpConstructMat3,
+ EOpConstructMat4,
+ EOpConstructStruct,
+
+ //
+ // moves
+ //
+
+ EOpAssign,
+ EOpInitialize,
+ EOpAddAssign,
+ EOpSubAssign,
+ EOpMulAssign,
+ EOpVectorTimesMatrixAssign,
+ EOpVectorTimesScalarAssign,
+ EOpMatrixTimesScalarAssign,
+ EOpMatrixTimesMatrixAssign,
+ EOpDivAssign
+};
+
+extern const char* getOperatorString(TOperator op);
+
+class TIntermTraverser;
+class TIntermAggregate;
+class TIntermBinary;
+class TIntermUnary;
+class TIntermConstantUnion;
+class TIntermSelection;
+class TIntermTyped;
+class TIntermSymbol;
+class TIntermLoop;
+class TInfoSink;
+
+//
+// Base class for the tree nodes
+//
+class TIntermNode {
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TIntermNode() {
+ // TODO: Move this to TSourceLoc constructor
+ // after getting rid of TPublicType.
+ line.first_file = line.last_file = 0;
+ line.first_line = line.last_line = 0;
+ }
+ virtual ~TIntermNode() { }
+
+ const TSourceLoc& getLine() const { return line; }
+ void setLine(const TSourceLoc& l) { line = l; }
+
+ virtual void traverse(TIntermTraverser*) = 0;
+ virtual TIntermTyped* getAsTyped() { return 0; }
+ virtual TIntermConstantUnion* getAsConstantUnion() { return 0; }
+ virtual TIntermAggregate* getAsAggregate() { return 0; }
+ virtual TIntermBinary* getAsBinaryNode() { return 0; }
+ virtual TIntermUnary* getAsUnaryNode() { return 0; }
+ virtual TIntermSelection* getAsSelectionNode() { return 0; }
+ virtual TIntermSymbol* getAsSymbolNode() { return 0; }
+ virtual TIntermLoop* getAsLoopNode() { return 0; }
+
+protected:
+ TSourceLoc line;
+};
+
+//
+// This is just to help yacc.
+//
+struct TIntermNodePair {
+ TIntermNode* node1;
+ TIntermNode* node2;
+};
+
+//
+// Intermediate class for nodes that have a type.
+//
+class TIntermTyped : public TIntermNode {
+public:
+ TIntermTyped(const TType& t) : type(t) { }
+ virtual TIntermTyped* getAsTyped() { return this; }
+
+ void setType(const TType& t) { type = t; }
+ const TType& getType() const { return type; }
+ TType* getTypePointer() { return &type; }
+
+ TBasicType getBasicType() const { return type.getBasicType(); }
+ TQualifier getQualifier() const { return type.getQualifier(); }
+ TPrecision getPrecision() const { return type.getPrecision(); }
+ int getNominalSize() const { return type.getNominalSize(); }
+
+ bool isMatrix() const { return type.isMatrix(); }
+ bool isArray() const { return type.isArray(); }
+ bool isVector() const { return type.isVector(); }
+ bool isScalar() const { return type.isScalar(); }
+ const char* getBasicString() const { return type.getBasicString(); }
+ const char* getQualifierString() const { return type.getQualifierString(); }
+ TString getCompleteString() const { return type.getCompleteString(); }
+
+ int totalRegisterCount() const { return type.totalRegisterCount(); }
+ int elementRegisterCount() const { return type.elementRegisterCount(); }
+ int getArraySize() const { return type.getArraySize(); }
+
+protected:
+ TType type;
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+enum TLoopType {
+ ELoopFor,
+ ELoopWhile,
+ ELoopDoWhile
+};
+
+class TIntermLoop : public TIntermNode {
+public:
+ TIntermLoop(TLoopType aType,
+ TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr,
+ TIntermNode* aBody) :
+ type(aType),
+ init(aInit),
+ cond(aCond),
+ expr(aExpr),
+ body(aBody),
+ unrollFlag(false) { }
+
+ virtual TIntermLoop* getAsLoopNode() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ TLoopType getType() const { return type; }
+ TIntermNode* getInit() { return init; }
+ TIntermTyped* getCondition() { return cond; }
+ TIntermTyped* getExpression() { return expr; }
+ TIntermNode* getBody() { return body; }
+
+ void setUnrollFlag(bool flag) { unrollFlag = flag; }
+ bool getUnrollFlag() { return unrollFlag; }
+
+protected:
+ TLoopType type;
+ TIntermNode* init; // for-loop initialization
+ TIntermTyped* cond; // loop exit condition
+ TIntermTyped* expr; // for-loop expression
+ TIntermNode* body; // loop body
+
+ bool unrollFlag; // Whether the loop should be unrolled or not.
+};
+
+//
+// Handle break, continue, return, and kill.
+//
+class TIntermBranch : public TIntermNode {
+public:
+ TIntermBranch(TOperator op, TIntermTyped* e) :
+ flowOp(op),
+ expression(e) { }
+
+ virtual void traverse(TIntermTraverser*);
+
+ TOperator getFlowOp() { return flowOp; }
+ TIntermTyped* getExpression() { return expression; }
+
+protected:
+ TOperator flowOp;
+ TIntermTyped* expression; // non-zero except for "return exp;" statements
+};
+
+//
+// Nodes that correspond to symbols or constants in the source code.
+//
+class TIntermSymbol : public TIntermTyped {
+public:
+ // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
+ // per process globalpoolallocator, then it causes increased memory usage per compile
+ // it is essential to use "symbol = sym" to assign to symbol
+ TIntermSymbol(int i, const TString& sym, const TType& t) :
+ TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; }
+
+ int getId() const { return id; }
+ const TString& getSymbol() const { return symbol; }
+
+ void setId(int newId) { id = newId; }
+ void setSymbol(const TString& sym) { symbol = sym; }
+
+ const TString& getOriginalSymbol() const { return originalSymbol; }
+
+ virtual void traverse(TIntermTraverser*);
+ virtual TIntermSymbol* getAsSymbolNode() { return this; }
+
+protected:
+ int id;
+ TString symbol;
+ TString originalSymbol;
+};
+
+class TIntermConstantUnion : public TIntermTyped {
+public:
+ TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
+
+ ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
+
+ int getIConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getIConst() : 0; }
+ float getFConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getFConst() : 0.0f; }
+ bool getBConst(int index) const { return unionArrayPointer ? unionArrayPointer[index].getBConst() : false; }
+
+ virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&);
+
+protected:
+ ConstantUnion *unionArrayPointer;
+};
+
+//
+// Intermediate class for node types that hold operators.
+//
+class TIntermOperator : public TIntermTyped {
+public:
+ TOperator getOp() const { return op; }
+ void setOp(TOperator o) { op = o; }
+
+ bool modifiesState() const;
+ bool isConstructor() const;
+
+protected:
+ TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
+ TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
+ TOperator op;
+};
+
+//
+// Nodes for all the basic binary math operators.
+//
+class TIntermBinary : public TIntermOperator {
+public:
+ TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {}
+
+ virtual TIntermBinary* getAsBinaryNode() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ void setLeft(TIntermTyped* n) { left = n; }
+ void setRight(TIntermTyped* n) { right = n; }
+ TIntermTyped* getLeft() const { return left; }
+ TIntermTyped* getRight() const { return right; }
+ bool promote(TInfoSink&);
+
+ void setAddIndexClamp() { addIndexClamp = true; }
+ bool getAddIndexClamp() { return addIndexClamp; }
+
+protected:
+ TIntermTyped* left;
+ TIntermTyped* right;
+
+ // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
+ bool addIndexClamp;
+};
+
+//
+// Nodes for unary math operators.
+//
+class TIntermUnary : public TIntermOperator {
+public:
+ TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
+ TIntermUnary(TOperator o) : TIntermOperator(o), operand(0), useEmulatedFunction(false) {}
+
+ virtual void traverse(TIntermTraverser*);
+ virtual TIntermUnary* getAsUnaryNode() { return this; }
+
+ void setOperand(TIntermTyped* o) { operand = o; }
+ TIntermTyped* getOperand() { return operand; }
+ bool promote(TInfoSink&);
+
+ void setUseEmulatedFunction() { useEmulatedFunction = true; }
+ bool getUseEmulatedFunction() { return useEmulatedFunction; }
+
+protected:
+ TIntermTyped* operand;
+
+ // If set to true, replace the built-in function call with an emulated one
+ // to work around driver bugs.
+ bool useEmulatedFunction;
+};
+
+typedef TVector<TIntermNode*> TIntermSequence;
+typedef TVector<int> TQualifierList;
+
+//
+// Nodes that operate on an arbitrary sized set of children.
+//
+class TIntermAggregate : public TIntermOperator {
+public:
+ TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), useEmulatedFunction(false) { }
+ TIntermAggregate(TOperator o) : TIntermOperator(o), useEmulatedFunction(false) { }
+ ~TIntermAggregate() { }
+
+ virtual TIntermAggregate* getAsAggregate() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ TIntermSequence& getSequence() { return sequence; }
+
+ void setName(const TString& n) { name = n; }
+ const TString& getName() const { return name; }
+
+ void setUserDefined() { userDefined = true; }
+ bool isUserDefined() const { return userDefined; }
+
+ void setOptimize(bool o) { optimize = o; }
+ bool getOptimize() { return optimize; }
+ void setDebug(bool d) { debug = d; }
+ bool getDebug() { return debug; }
+
+ void setUseEmulatedFunction() { useEmulatedFunction = true; }
+ bool getUseEmulatedFunction() { return useEmulatedFunction; }
+
+protected:
+ TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
+ TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
+ TIntermSequence sequence;
+ TString name;
+ bool userDefined; // used for user defined function names
+
+ bool optimize;
+ bool debug;
+
+ // If set to true, replace the built-in function call with an emulated one
+ // to work around driver bugs.
+ bool useEmulatedFunction;
+};
+
+//
+// For if tests. Simplified since there is no switch statement.
+//
+class TIntermSelection : public TIntermTyped {
+public:
+ TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
+ TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+ TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
+ TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+
+ virtual void traverse(TIntermTraverser*);
+
+ bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
+ TIntermNode* getCondition() const { return condition; }
+ TIntermNode* getTrueBlock() const { return trueBlock; }
+ TIntermNode* getFalseBlock() const { return falseBlock; }
+ TIntermSelection* getAsSelectionNode() { return this; }
+
+protected:
+ TIntermTyped* condition;
+ TIntermNode* trueBlock;
+ TIntermNode* falseBlock;
+};
+
+enum Visit
+{
+ PreVisit,
+ InVisit,
+ PostVisit
+};
+
+//
+// For traversing the tree. User should derive from this,
+// put their traversal specific data in it, and then pass
+// it to a Traverse method.
+//
+// When using this, just fill in the methods for nodes you want visited.
+// Return false from a pre-visit to skip visiting that node's subtree.
+//
+class TIntermTraverser
+{
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
+ preVisit(preVisit),
+ inVisit(inVisit),
+ postVisit(postVisit),
+ rightToLeft(rightToLeft),
+ depth(0),
+ maxDepth(0) {}
+ virtual ~TIntermTraverser() {};
+
+ virtual void visitSymbol(TIntermSymbol*) {}
+ virtual void visitConstantUnion(TIntermConstantUnion*) {}
+ virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
+ virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}
+ virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;}
+ virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
+ virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
+ virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
+
+ int getMaxDepth() const {return maxDepth;}
+ void incrementDepth() {depth++; maxDepth = std::max(maxDepth, depth); }
+ void decrementDepth() {depth--;}
+
+ // Return the original name if hash function pointer is NULL;
+ // otherwise return the hashed name.
+ static TString hash(const TString& name, ShHashFunction64 hashFunction);
+
+ const bool preVisit;
+ const bool inVisit;
+ const bool postVisit;
+ const bool rightToLeft;
+
+protected:
+ int depth;
+ int maxDepth;
+};
+
+#endif // __INTERMEDIATE_H
diff --git a/src/compiler/localintermediate.h b/src/compiler/localintermediate.h
new file mode 100644
index 00000000..ccbc4017
--- /dev/null
+++ b/src/compiler/localintermediate.h
@@ -0,0 +1,57 @@
+//
+// 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.
+//
+
+#ifndef _LOCAL_INTERMEDIATE_INCLUDED_
+#define _LOCAL_INTERMEDIATE_INCLUDED_
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+#include "compiler/SymbolTable.h"
+
+struct TVectorFields {
+ int offsets[4];
+ int num;
+};
+
+//
+// Set of helper functions to help parse and build the tree.
+//
+class TInfoSink;
+class TIntermediate {
+public:
+ POOL_ALLOCATOR_NEW_DELETE();
+ TIntermediate(TInfoSink& i) : infoSink(i) { }
+
+ TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TSourceLoc&);
+ TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
+ TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&, TSymbolTable&);
+ TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
+ TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, const TSourceLoc&);
+ TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, const TSourceLoc&, TSymbolTable&);
+ TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
+ TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
+ TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, const TSourceLoc&);
+ TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
+ TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
+ TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
+ TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, const TSourceLoc&);
+ TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
+ bool parseConstTree(const TSourceLoc&, TIntermNode*, ConstantUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false);
+ TIntermNode* addLoop(TLoopType, TIntermNode*, TIntermTyped*, TIntermTyped*, TIntermNode*, const TSourceLoc&);
+ TIntermBranch* addBranch(TOperator, const TSourceLoc&);
+ TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
+ TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&);
+ bool postProcess(TIntermNode*);
+ void remove(TIntermNode*);
+ void outputTree(TIntermNode*);
+
+private:
+ void operator=(TIntermediate&); // prevent assignments
+
+ TInfoSink& infoSink;
+};
+
+#endif // _LOCAL_INTERMEDIATE_INCLUDED_
diff --git a/src/compiler/osinclude.h b/src/compiler/osinclude.h
new file mode 100644
index 00000000..d8bb1a79
--- /dev/null
+++ b/src/compiler/osinclude.h
@@ -0,0 +1,65 @@
+//
+// 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.
+//
+
+#ifndef __OSINCLUDE_H
+#define __OSINCLUDE_H
+
+//
+// This file contains contains os-specific datatypes and
+// declares any os-specific functions.
+//
+
+#if defined(_WIN32) || defined(_WIN64)
+#define ANGLE_OS_WIN
+#elif defined(__APPLE__) || defined(__linux__) || \
+ defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__sun) || defined(ANDROID) || \
+ defined(__GLIBC__) || defined(__GNU__) || \
+ defined(__QNX__)
+#define ANGLE_OS_POSIX
+#else
+#error Unsupported platform.
+#endif
+
+#if defined(ANGLE_OS_WIN)
+#define STRICT
+#define VC_EXTRALEAN 1
+#include <windows.h>
+#elif defined(ANGLE_OS_POSIX)
+#include <pthread.h>
+#include <semaphore.h>
+#include <errno.h>
+#endif // ANGLE_OS_WIN
+
+
+#include "compiler/debug.h"
+
+//
+// Thread Local Storage Operations
+//
+#if defined(ANGLE_OS_WIN)
+typedef DWORD OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES)
+#elif defined(ANGLE_OS_POSIX)
+typedef pthread_key_t OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX (static_cast<OS_TLSIndex>(-1))
+#endif // ANGLE_OS_WIN
+
+OS_TLSIndex OS_AllocTLSIndex();
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue);
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex);
+
+inline void* OS_GetTLSValue(OS_TLSIndex nIndex)
+{
+ ASSERT(nIndex != OS_INVALID_TLS_INDEX);
+#if defined(ANGLE_OS_WIN)
+ return TlsGetValue(nIndex);
+#elif defined(ANGLE_OS_POSIX)
+ return pthread_getspecific(nIndex);
+#endif // ANGLE_OS_WIN
+}
+
+#endif // __OSINCLUDE_H
diff --git a/src/compiler/ossource_posix.cpp b/src/compiler/ossource_posix.cpp
new file mode 100644
index 00000000..1e1e699a
--- /dev/null
+++ b/src/compiler/ossource_posix.cpp
@@ -0,0 +1,64 @@
+//
+// 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.
+//
+
+//
+// This file contains the posix specific functions
+//
+#include "compiler/osinclude.h"
+
+#if !defined(ANGLE_OS_POSIX)
+#error Trying to build a posix specific file in a non-posix build.
+#endif
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ pthread_key_t pPoolIndex;
+
+ //
+ // Create global pool key.
+ //
+ if ((pthread_key_create(&pPoolIndex, NULL)) != 0) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return false;
+ }
+ else {
+ return pPoolIndex;
+ }
+}
+
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (pthread_setspecific(nIndex, lpvValue) == 0)
+ return true;
+ else
+ return false;
+}
+
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ //
+ // Delete the global pool key.
+ //
+ if (pthread_key_delete(nIndex) == 0)
+ return true;
+ else
+ return false;
+}
diff --git a/src/compiler/ossource_win.cpp b/src/compiler/ossource_win.cpp
new file mode 100644
index 00000000..89922fef
--- /dev/null
+++ b/src/compiler/ossource_win.cpp
@@ -0,0 +1,57 @@
+//
+// 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.
+//
+
+#include "compiler/osinclude.h"
+//
+// This file contains contains the window's specific functions
+//
+
+#if !defined(ANGLE_OS_WIN)
+#error Trying to build a windows specific file in a non windows build.
+#endif
+
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ DWORD dwIndex = TlsAlloc();
+ if (dwIndex == TLS_OUT_OF_INDEXES) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return OS_INVALID_TLS_INDEX;
+ }
+
+ return dwIndex;
+}
+
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (TlsSetValue(nIndex, lpvValue))
+ return true;
+ else
+ return false;
+}
+
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (TlsFree(nIndex))
+ return true;
+ else
+ return false;
+}
diff --git a/src/compiler/parseConst.cpp b/src/compiler/parseConst.cpp
new file mode 100644
index 00000000..1cc5db8d
--- /dev/null
+++ b/src/compiler/parseConst.cpp
@@ -0,0 +1,245 @@
+//
+// 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.
+//
+
+#include "compiler/ParseHelper.h"
+
+//
+// Use this class to carry along data from node to node in
+// the traversal
+//
+class TConstTraverser : public TIntermTraverser {
+public:
+ TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t)
+ : error(false),
+ index(0),
+ unionArray(cUnion),
+ type(t),
+ constructorType(constructType),
+ singleConstantParam(singleConstParam),
+ infoSink(sink),
+ symbolTable(symTable),
+ size(0),
+ isMatrix(false),
+ matrixSize(0) {
+ }
+
+ bool error;
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+
+ size_t index;
+ ConstantUnion *unionArray;
+ TType type;
+ TOperator constructorType;
+ bool singleConstantParam;
+ TInfoSink& infoSink;
+ TSymbolTable& symbolTable;
+ size_t size; // size of the constructor ( 4 for vec4)
+ bool isMatrix;
+ size_t matrixSize; // dimension of the matrix (nominal size and not the instance size)
+};
+
+//
+// The rest of the file are the traversal functions. The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. If you process children yourself,
+// return false.
+//
+
+void TConstTraverser::visitSymbol(TIntermSymbol* node)
+{
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Symbol Node found in constant constructor");
+ return;
+
+}
+
+bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node)
+{
+ TQualifier qualifier = node->getType().getQualifier();
+
+ if (qualifier != EvqConst) {
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
+ error = true;
+ return false;
+ }
+
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Binary Node found in constant constructor");
+
+ return false;
+}
+
+bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
+ error = true;
+ return false;
+}
+
+bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ if (!node->isConstructor() && node->getOp() != EOpComma) {
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, node->getLine(), buf.c_str());
+ error = true;
+ return false;
+ }
+
+ if (node->getSequence().size() == 0) {
+ error = true;
+ return false;
+ }
+
+ bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
+ if (flag)
+ {
+ singleConstantParam = true;
+ constructorType = node->getOp();
+ size = node->getType().getObjectSize();
+
+ if (node->getType().isMatrix()) {
+ isMatrix = true;
+ matrixSize = node->getType().getNominalSize();
+ }
+ }
+
+ for (TIntermSequence::iterator p = node->getSequence().begin();
+ p != node->getSequence().end(); p++) {
+
+ if (node->getOp() == EOpComma)
+ index = 0;
+
+ (*p)->traverse(this);
+ }
+ if (flag)
+ {
+ singleConstantParam = false;
+ constructorType = EOpNull;
+ size = 0;
+ isMatrix = false;
+ matrixSize = 0;
+ }
+ return false;
+}
+
+bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node)
+{
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Selection Node found in constant constructor");
+ error = true;
+ return false;
+}
+
+void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+ if (!node->getUnionArrayPointer())
+ {
+ // The constant was not initialized, this should already have been logged
+ assert(infoSink.info.size() != 0);
+ return;
+ }
+
+ ConstantUnion* leftUnionArray = unionArray;
+ size_t instanceSize = type.getObjectSize();
+
+ if (index >= instanceSize)
+ return;
+
+ if (!singleConstantParam) {
+ size_t size = node->getType().getObjectSize();
+
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ for (size_t i = 0; i < size; i++) {
+ if (index >= instanceSize)
+ return;
+ leftUnionArray[index] = rightUnionArray[i];
+
+ (index)++;
+ }
+ } else {
+ size_t totalSize = index + size;
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ if (!isMatrix) {
+ size_t count = 0;
+ for (size_t i = index; i < totalSize; i++) {
+ if (i >= instanceSize)
+ return;
+
+ leftUnionArray[i] = rightUnionArray[count];
+
+ (index)++;
+
+ if (node->getType().getObjectSize() > 1)
+ count++;
+ }
+ } else { // for matrix constructors
+ size_t count = 0;
+ size_t element = index;
+ for (size_t i = index; i < totalSize; i++) {
+ if (i >= instanceSize)
+ return;
+ if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 )
+ leftUnionArray[i] = rightUnionArray[count];
+ else
+ leftUnionArray[i].setFConst(0.0f);
+
+ (index)++;
+
+ if (node->getType().getObjectSize() > 1)
+ count++;
+ }
+ }
+ }
+}
+
+bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node)
+{
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Loop Node found in constant constructor");
+ error = true;
+ return false;
+}
+
+bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node)
+{
+ infoSink.info.message(EPrefixInternalError, node->getLine(), "Branch Node found in constant constructor");
+ error = true;
+ return false;
+}
+
+//
+// This function is the one to call externally to start the traversal.
+// Individual functions can be initialized to 0 to skip processing of that
+// type of node. It's children will still be processed.
+//
+bool TIntermediate::parseConstTree(const TSourceLoc& line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam)
+{
+ if (root == 0)
+ return false;
+
+ TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t);
+
+ root->traverse(&it);
+ if (it.error)
+ return true;
+ else
+ return false;
+}
diff --git a/src/compiler/preprocessor/64bit-tokenizer-safety.patch b/src/compiler/preprocessor/64bit-tokenizer-safety.patch
new file mode 100644
index 00000000..7cb06160
--- /dev/null
+++ b/src/compiler/preprocessor/64bit-tokenizer-safety.patch
@@ -0,0 +1,159 @@
+--- a/src/compiler/preprocessor/Tokenizer.cpp
++++ b/src/compiler/preprocessor/Tokenizer.cpp
+@@ -56,6 +56,7 @@ typedef int16_t flex_int16_t;
+ typedef uint16_t flex_uint16_t;
+ typedef int32_t flex_int32_t;
+ typedef uint32_t flex_uint32_t;
++typedef uint64_t flex_uint64_t;
+ #else
+ typedef signed char flex_int8_t;
+ typedef short int flex_int16_t;
+@@ -179,6 +180,11 @@ typedef void* yyscan_t;
+ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+ #endif
+
++#ifndef YY_TYPEDEF_YY_SIZE_T
++#define YY_TYPEDEF_YY_SIZE_T
++typedef size_t yy_size_t;
++#endif
++
+ #define EOB_ACT_CONTINUE_SCAN 0
+ #define EOB_ACT_END_OF_FILE 1
+ #define EOB_ACT_LAST_MATCH 2
+@@ -201,11 +207,6 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+ #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+-#ifndef YY_TYPEDEF_YY_SIZE_T
+-#define YY_TYPEDEF_YY_SIZE_T
+-typedef size_t yy_size_t;
+-#endif
+-
+ #ifndef YY_STRUCT_YY_BUFFER_STATE
+ #define YY_STRUCT_YY_BUFFER_STATE
+ struct yy_buffer_state
+@@ -223,7 +224,7 @@ struct yy_buffer_state
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+- int yy_n_chars;
++ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+@@ -302,7 +303,7 @@ static void pp_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+ YY_BUFFER_STATE pp_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+ YY_BUFFER_STATE pp_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+-YY_BUFFER_STATE pp_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
++YY_BUFFER_STATE pp_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+ void *ppalloc (yy_size_t ,yyscan_t yyscanner );
+ void *pprealloc (void *,yy_size_t ,yyscan_t yyscanner );
+@@ -353,7 +354,7 @@ static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+ */
+ #define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+- yyleng = (size_t) (yy_cp - yy_bp); \
++ yyleng = (yy_size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+@@ -579,8 +580,8 @@ struct yyguts_t
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+- int yy_n_chars;
+- int yyleng_r;
++ yy_size_t yy_n_chars;
++ yy_size_t yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+@@ -637,7 +638,7 @@ FILE *ppget_out (yyscan_t yyscanner );
+
+ void ppset_out (FILE * out_str ,yyscan_t yyscanner );
+
+-int ppget_leng (yyscan_t yyscanner );
++yy_size_t ppget_leng (yyscan_t yyscanner );
+
+ char *ppget_text (yyscan_t yyscanner );
+
+@@ -704,7 +705,7 @@ static int input (yyscan_t yyscanner );
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+- int n; \
++ yy_size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+@@ -1338,7 +1339,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ else
+ {
+- int num_to_read =
++ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+@@ -1352,7 +1353,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ if ( b->yy_is_our_buffer )
+ {
+- int new_size = b->yy_buf_size * 2;
++ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+@@ -1383,7 +1384,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+- yyg->yy_n_chars, (size_t) num_to_read );
++ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+@@ -1508,7 +1509,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
+
+ else
+ { /* need more input */
+- int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
++ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+@@ -1788,7 +1789,7 @@ void pppop_buffer_state (yyscan_t yyscanner)
+ */
+ static void ppensure_buffer_stack (yyscan_t yyscanner)
+ {
+- int num_to_alloc;
++ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+@@ -1886,12 +1887,11 @@ YY_BUFFER_STATE pp_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+-YY_BUFFER_STATE pp_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
++YY_BUFFER_STATE pp_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+- yy_size_t n;
+- int i;
++ yy_size_t n, i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+@@ -2001,7 +2001,7 @@ FILE *ppget_out (yyscan_t yyscanner)
+ /** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+-int ppget_leng (yyscan_t yyscanner)
++yy_size_t ppget_leng (yyscan_t yyscanner)
+ {
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
diff --git a/src/compiler/preprocessor/DiagnosticsBase.cpp b/src/compiler/preprocessor/DiagnosticsBase.cpp
new file mode 100644
index 00000000..3e22e1f1
--- /dev/null
+++ b/src/compiler/preprocessor/DiagnosticsBase.cpp
@@ -0,0 +1,127 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "DiagnosticsBase.h"
+
+#include <cassert>
+
+namespace pp
+{
+
+Diagnostics::~Diagnostics()
+{
+}
+
+void Diagnostics::report(ID id,
+ const SourceLocation& loc,
+ const std::string& text)
+{
+ // TODO(alokp): Keep a count of errors and warnings.
+ print(id, loc, text);
+}
+
+Diagnostics::Severity Diagnostics::severity(ID id)
+{
+ if ((id > ERROR_BEGIN) && (id < ERROR_END))
+ return ERROR;
+
+ if ((id > WARNING_BEGIN) && (id < WARNING_END))
+ return WARNING;
+
+ assert(false);
+ return ERROR;
+}
+
+std::string Diagnostics::message(ID id)
+{
+ switch (id)
+ {
+ // Errors begin.
+ case INTERNAL_ERROR:
+ return "internal error";
+ case OUT_OF_MEMORY:
+ return "out of memory";
+ case INVALID_CHARACTER:
+ return "invalid character";
+ case INVALID_NUMBER:
+ return "invalid number";
+ case INTEGER_OVERFLOW:
+ return "integer overflow";
+ case FLOAT_OVERFLOW:
+ return "float overflow";
+ case TOKEN_TOO_LONG:
+ return "token too long";
+ case INVALID_EXPRESSION:
+ return "invalid expression";
+ case DIVISION_BY_ZERO:
+ return "division by zero";
+ case EOF_IN_COMMENT:
+ return "unexpected end of file found in comment";
+ case UNEXPECTED_TOKEN:
+ return "unexpected token";
+ case DIRECTIVE_INVALID_NAME:
+ return "invalid directive name";
+ case MACRO_NAME_RESERVED:
+ return "macro name is reserved";
+ case MACRO_REDEFINED:
+ return "macro redefined";
+ case MACRO_PREDEFINED_REDEFINED:
+ return "predefined macro redefined";
+ case MACRO_PREDEFINED_UNDEFINED:
+ return "predefined macro undefined";
+ case MACRO_UNTERMINATED_INVOCATION:
+ return "unterminated macro invocation";
+ case MACRO_TOO_FEW_ARGS:
+ return "Not enough arguments for macro";
+ case MACRO_TOO_MANY_ARGS:
+ return "Too many arguments for macro";
+ case CONDITIONAL_ENDIF_WITHOUT_IF:
+ return "unexpected #endif found without a matching #if";
+ case CONDITIONAL_ELSE_WITHOUT_IF:
+ return "unexpected #else found without a matching #if";
+ case CONDITIONAL_ELSE_AFTER_ELSE:
+ return "unexpected #else found after another #else";
+ case CONDITIONAL_ELIF_WITHOUT_IF:
+ return "unexpected #elif found without a matching #if";
+ case CONDITIONAL_ELIF_AFTER_ELSE:
+ return "unexpected #elif found after #else";
+ case CONDITIONAL_UNTERMINATED:
+ return "unexpected end of file found in conditional block";
+ case INVALID_EXTENSION_NAME:
+ return "invalid extension name";
+ case INVALID_EXTENSION_BEHAVIOR:
+ return "invalid extension behavior";
+ case INVALID_EXTENSION_DIRECTIVE:
+ return "invalid extension directive";
+ case INVALID_VERSION_NUMBER:
+ return "invalid version number";
+ case INVALID_VERSION_DIRECTIVE:
+ return "invalid version directive";
+ case VERSION_NOT_FIRST_STATEMENT:
+ return "#version directive must occur before anything else, "
+ "except for comments and white space";
+ case INVALID_LINE_NUMBER:
+ return "invalid line number";
+ case INVALID_FILE_NUMBER:
+ return "invalid file number";
+ case INVALID_LINE_DIRECTIVE:
+ return "invalid line directive";
+ // Errors end.
+ // Warnings begin.
+ case EOF_IN_DIRECTIVE:
+ return "unexpected end of file found in directive";
+ case CONDITIONAL_UNEXPECTED_TOKEN:
+ return "unexpected token after conditional expression";
+ case UNRECOGNIZED_PRAGMA:
+ return "unrecognized pragma";
+ // Warnings end.
+ default:
+ assert(false);
+ return "";
+ }
+}
+
+} // namespace pp
diff --git a/src/compiler/preprocessor/DiagnosticsBase.h b/src/compiler/preprocessor/DiagnosticsBase.h
new file mode 100644
index 00000000..07bc4118
--- /dev/null
+++ b/src/compiler/preprocessor/DiagnosticsBase.h
@@ -0,0 +1,87 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
+#define COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
+
+#include <string>
+
+namespace pp
+{
+
+struct SourceLocation;
+
+// Base class for reporting diagnostic messages.
+// Derived classes are responsible for formatting and printing the messages.
+class Diagnostics
+{
+ public:
+ enum Severity
+ {
+ ERROR,
+ WARNING
+ };
+ enum ID
+ {
+ ERROR_BEGIN,
+ INTERNAL_ERROR,
+ OUT_OF_MEMORY,
+ INVALID_CHARACTER,
+ INVALID_NUMBER,
+ INTEGER_OVERFLOW,
+ FLOAT_OVERFLOW,
+ TOKEN_TOO_LONG,
+ INVALID_EXPRESSION,
+ DIVISION_BY_ZERO,
+ EOF_IN_COMMENT,
+ UNEXPECTED_TOKEN,
+ DIRECTIVE_INVALID_NAME,
+ MACRO_NAME_RESERVED,
+ MACRO_REDEFINED,
+ MACRO_PREDEFINED_REDEFINED,
+ MACRO_PREDEFINED_UNDEFINED,
+ MACRO_UNTERMINATED_INVOCATION,
+ MACRO_TOO_FEW_ARGS,
+ MACRO_TOO_MANY_ARGS,
+ CONDITIONAL_ENDIF_WITHOUT_IF,
+ CONDITIONAL_ELSE_WITHOUT_IF,
+ CONDITIONAL_ELSE_AFTER_ELSE,
+ CONDITIONAL_ELIF_WITHOUT_IF,
+ CONDITIONAL_ELIF_AFTER_ELSE,
+ CONDITIONAL_UNTERMINATED,
+ INVALID_EXTENSION_NAME,
+ INVALID_EXTENSION_BEHAVIOR,
+ INVALID_EXTENSION_DIRECTIVE,
+ INVALID_VERSION_NUMBER,
+ INVALID_VERSION_DIRECTIVE,
+ VERSION_NOT_FIRST_STATEMENT,
+ INVALID_LINE_NUMBER,
+ INVALID_FILE_NUMBER,
+ INVALID_LINE_DIRECTIVE,
+ ERROR_END,
+
+ WARNING_BEGIN,
+ EOF_IN_DIRECTIVE,
+ CONDITIONAL_UNEXPECTED_TOKEN,
+ UNRECOGNIZED_PRAGMA,
+ WARNING_END
+ };
+
+ virtual ~Diagnostics();
+
+ void report(ID id, const SourceLocation& loc, const std::string& text);
+
+ protected:
+ Severity severity(ID id);
+ std::string message(ID id);
+
+ virtual void print(ID id,
+ const SourceLocation& loc,
+ const std::string& text) = 0;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_DIAGNOSTICS_H_
diff --git a/src/compiler/preprocessor/DirectiveHandlerBase.cpp b/src/compiler/preprocessor/DirectiveHandlerBase.cpp
new file mode 100644
index 00000000..ef35c6ed
--- /dev/null
+++ b/src/compiler/preprocessor/DirectiveHandlerBase.cpp
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "DirectiveHandlerBase.h"
+
+namespace pp
+{
+
+DirectiveHandler::~DirectiveHandler()
+{
+}
+
+} // namespace pp
diff --git a/src/compiler/preprocessor/DirectiveHandlerBase.h b/src/compiler/preprocessor/DirectiveHandlerBase.h
new file mode 100644
index 00000000..2aaeec28
--- /dev/null
+++ b/src/compiler/preprocessor/DirectiveHandlerBase.h
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
+#define COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
+
+#include <string>
+
+namespace pp
+{
+
+struct SourceLocation;
+
+// Base class for handling directives.
+// Preprocessor uses this class to notify the clients about certain
+// preprocessor directives. Derived classes are responsible for
+// handling them in an appropriate manner.
+class DirectiveHandler
+{
+ public:
+ virtual ~DirectiveHandler();
+
+ virtual void handleError(const SourceLocation& loc,
+ const std::string& msg) = 0;
+
+ // Handle pragma of form: #pragma name[(value)]
+ virtual void handlePragma(const SourceLocation& loc,
+ const std::string& name,
+ const std::string& value) = 0;
+
+ virtual void handleExtension(const SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior) = 0;
+
+ virtual void handleVersion(const SourceLocation& loc,
+ int version) = 0;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_
diff --git a/src/compiler/preprocessor/DirectiveParser.cpp b/src/compiler/preprocessor/DirectiveParser.cpp
new file mode 100644
index 00000000..94dfdf51
--- /dev/null
+++ b/src/compiler/preprocessor/DirectiveParser.cpp
@@ -0,0 +1,932 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "DirectiveParser.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <sstream>
+
+#include "DiagnosticsBase.h"
+#include "DirectiveHandlerBase.h"
+#include "ExpressionParser.h"
+#include "MacroExpander.h"
+#include "Token.h"
+#include "Tokenizer.h"
+
+namespace {
+enum DirectiveType
+{
+ DIRECTIVE_NONE,
+ DIRECTIVE_DEFINE,
+ DIRECTIVE_UNDEF,
+ DIRECTIVE_IF,
+ DIRECTIVE_IFDEF,
+ DIRECTIVE_IFNDEF,
+ DIRECTIVE_ELSE,
+ DIRECTIVE_ELIF,
+ DIRECTIVE_ENDIF,
+ DIRECTIVE_ERROR,
+ DIRECTIVE_PRAGMA,
+ DIRECTIVE_EXTENSION,
+ DIRECTIVE_VERSION,
+ DIRECTIVE_LINE
+};
+} // namespace
+
+static DirectiveType getDirective(const pp::Token* token)
+{
+ static const std::string kDirectiveDefine("define");
+ static const std::string kDirectiveUndef("undef");
+ static const std::string kDirectiveIf("if");
+ static const std::string kDirectiveIfdef("ifdef");
+ static const std::string kDirectiveIfndef("ifndef");
+ static const std::string kDirectiveElse("else");
+ static const std::string kDirectiveElif("elif");
+ static const std::string kDirectiveEndif("endif");
+ static const std::string kDirectiveError("error");
+ static const std::string kDirectivePragma("pragma");
+ static const std::string kDirectiveExtension("extension");
+ static const std::string kDirectiveVersion("version");
+ static const std::string kDirectiveLine("line");
+
+ if (token->type != pp::Token::IDENTIFIER)
+ return DIRECTIVE_NONE;
+
+ if (token->text == kDirectiveDefine)
+ return DIRECTIVE_DEFINE;
+ else if (token->text == kDirectiveUndef)
+ return DIRECTIVE_UNDEF;
+ else if (token->text == kDirectiveIf)
+ return DIRECTIVE_IF;
+ else if (token->text == kDirectiveIfdef)
+ return DIRECTIVE_IFDEF;
+ else if (token->text == kDirectiveIfndef)
+ return DIRECTIVE_IFNDEF;
+ else if (token->text == kDirectiveElse)
+ return DIRECTIVE_ELSE;
+ else if (token->text == kDirectiveElif)
+ return DIRECTIVE_ELIF;
+ else if (token->text == kDirectiveEndif)
+ return DIRECTIVE_ENDIF;
+ else if (token->text == kDirectiveError)
+ return DIRECTIVE_ERROR;
+ else if (token->text == kDirectivePragma)
+ return DIRECTIVE_PRAGMA;
+ else if (token->text == kDirectiveExtension)
+ return DIRECTIVE_EXTENSION;
+ else if (token->text == kDirectiveVersion)
+ return DIRECTIVE_VERSION;
+ else if (token->text == kDirectiveLine)
+ return DIRECTIVE_LINE;
+
+ return DIRECTIVE_NONE;
+}
+
+static bool isConditionalDirective(DirectiveType directive)
+{
+ switch (directive)
+ {
+ case DIRECTIVE_IF:
+ case DIRECTIVE_IFDEF:
+ case DIRECTIVE_IFNDEF:
+ case DIRECTIVE_ELSE:
+ case DIRECTIVE_ELIF:
+ case DIRECTIVE_ENDIF:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true if the token represents End Of Directive.
+static bool isEOD(const pp::Token* token)
+{
+ return (token->type == '\n') || (token->type == pp::Token::LAST);
+}
+
+static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
+{
+ while(!isEOD(token))
+ {
+ lexer->lex(token);
+ }
+}
+
+static bool isMacroNameReserved(const std::string& name)
+{
+ // Names prefixed with "GL_" are reserved.
+ if (name.substr(0, 3) == "GL_")
+ return true;
+
+ // Names containing two consecutive underscores are reserved.
+ if (name.find("__") != std::string::npos)
+ return true;
+
+ return false;
+}
+
+static bool isMacroPredefined(const std::string& name,
+ const pp::MacroSet& macroSet)
+{
+ pp::MacroSet::const_iterator iter = macroSet.find(name);
+ return iter != macroSet.end() ? iter->second.predefined : false;
+}
+
+namespace pp
+{
+
+class DefinedParser : public Lexer
+{
+ public:
+ DefinedParser(Lexer* lexer,
+ const MacroSet* macroSet,
+ Diagnostics* diagnostics) :
+ mLexer(lexer),
+ mMacroSet(macroSet),
+ mDiagnostics(diagnostics)
+ {
+ }
+
+ protected:
+ virtual void lex(Token* token)
+ {
+ static const std::string kDefined("defined");
+
+ mLexer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ return;
+ if (token->text != kDefined)
+ return;
+
+ bool paren = false;
+ mLexer->lex(token);
+ if (token->type == '(')
+ {
+ paren = true;
+ mLexer->lex(token);
+ }
+
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mLexer, token);
+ return;
+ }
+ MacroSet::const_iterator iter = mMacroSet->find(token->text);
+ std::string expression = iter != mMacroSet->end() ? "1" : "0";
+
+ if (paren)
+ {
+ mLexer->lex(token);
+ if (token->type != ')')
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mLexer, token);
+ return;
+ }
+ }
+
+ // We have a valid defined operator.
+ // Convert the current token into a CONST_INT token.
+ token->type = Token::CONST_INT;
+ token->text = expression;
+ }
+
+ private:
+ Lexer* mLexer;
+ const MacroSet* mMacroSet;
+ Diagnostics* mDiagnostics;
+};
+
+DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
+ MacroSet* macroSet,
+ Diagnostics* diagnostics,
+ DirectiveHandler* directiveHandler) :
+ mPastFirstStatement(false),
+ mTokenizer(tokenizer),
+ mMacroSet(macroSet),
+ mDiagnostics(diagnostics),
+ mDirectiveHandler(directiveHandler)
+{
+}
+
+void DirectiveParser::lex(Token* token)
+{
+ do
+ {
+ mTokenizer->lex(token);
+
+ if (token->type == Token::PP_HASH)
+ {
+ parseDirective(token);
+ mPastFirstStatement = true;
+ }
+
+ if (token->type == Token::LAST)
+ {
+ if (!mConditionalStack.empty())
+ {
+ const ConditionalBlock& block = mConditionalStack.back();
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,
+ block.location, block.type);
+ }
+ break;
+ }
+
+ } while (skipping() || (token->type == '\n'));
+
+ mPastFirstStatement = true;
+}
+
+void DirectiveParser::parseDirective(Token* token)
+{
+ assert(token->type == Token::PP_HASH);
+
+ mTokenizer->lex(token);
+ if (isEOD(token))
+ {
+ // Empty Directive.
+ return;
+ }
+
+ DirectiveType directive = getDirective(token);
+
+ // While in an excluded conditional block/group,
+ // we only parse conditional directives.
+ if (skipping() && !isConditionalDirective(directive))
+ {
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ switch(directive)
+ {
+ case DIRECTIVE_NONE:
+ mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ break;
+ case DIRECTIVE_DEFINE:
+ parseDefine(token);
+ break;
+ case DIRECTIVE_UNDEF:
+ parseUndef(token);
+ break;
+ case DIRECTIVE_IF:
+ parseIf(token);
+ break;
+ case DIRECTIVE_IFDEF:
+ parseIfdef(token);
+ break;
+ case DIRECTIVE_IFNDEF:
+ parseIfndef(token);
+ break;
+ case DIRECTIVE_ELSE:
+ parseElse(token);
+ break;
+ case DIRECTIVE_ELIF:
+ parseElif(token);
+ break;
+ case DIRECTIVE_ENDIF:
+ parseEndif(token);
+ break;
+ case DIRECTIVE_ERROR:
+ parseError(token);
+ break;
+ case DIRECTIVE_PRAGMA:
+ parsePragma(token);
+ break;
+ case DIRECTIVE_EXTENSION:
+ parseExtension(token);
+ break;
+ case DIRECTIVE_VERSION:
+ parseVersion(token);
+ break;
+ case DIRECTIVE_LINE:
+ parseLine(token);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ skipUntilEOD(mTokenizer, token);
+ if (token->type == Token::LAST)
+ {
+ mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
+ token->location, token->text);
+ }
+}
+
+void DirectiveParser::parseDefine(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_DEFINE);
+
+ mTokenizer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ return;
+ }
+ if (isMacroPredefined(token->text, *mMacroSet))
+ {
+ mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
+ token->location, token->text);
+ return;
+ }
+ if (isMacroNameReserved(token->text))
+ {
+ mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
+ token->location, token->text);
+ return;
+ }
+
+ Macro macro;
+ macro.type = Macro::kTypeObj;
+ macro.name = token->text;
+
+ mTokenizer->lex(token);
+ if (token->type == '(' && !token->hasLeadingSpace())
+ {
+ // Function-like macro. Collect arguments.
+ macro.type = Macro::kTypeFunc;
+ do {
+ mTokenizer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ break;
+ macro.parameters.push_back(token->text);
+
+ mTokenizer->lex(token); // Get ','.
+ } while (token->type == ',');
+
+ if (token->type != ')')
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location,
+ token->text);
+ return;
+ }
+ mTokenizer->lex(token); // Get ')'.
+ }
+
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ // Reset the token location because it is unnecessary in replacement
+ // list. Resetting it also allows us to reuse Token::equals() to
+ // compare macros.
+ token->location = SourceLocation();
+ macro.replacements.push_back(*token);
+ mTokenizer->lex(token);
+ }
+ if (!macro.replacements.empty())
+ {
+ // Whitespace preceding the replacement list is not considered part of
+ // the replacement list for either form of macro.
+ macro.replacements.front().setHasLeadingSpace(false);
+ }
+
+ // Check for macro redefinition.
+ MacroSet::const_iterator iter = mMacroSet->find(macro.name);
+ if (iter != mMacroSet->end() && !macro.equals(iter->second))
+ {
+ mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
+ token->location,
+ macro.name);
+ return;
+ }
+ mMacroSet->insert(std::make_pair(macro.name, macro));
+}
+
+void DirectiveParser::parseUndef(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_UNDEF);
+
+ mTokenizer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ return;
+ }
+
+ MacroSet::iterator iter = mMacroSet->find(token->text);
+ if (iter != mMacroSet->end())
+ {
+ if (iter->second.predefined)
+ {
+ mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+ token->location, token->text);
+ }
+ else
+ {
+ mMacroSet->erase(iter);
+ }
+ }
+
+ mTokenizer->lex(token);
+}
+
+void DirectiveParser::parseIf(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_IF);
+ parseConditionalIf(token);
+}
+
+void DirectiveParser::parseIfdef(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_IFDEF);
+ parseConditionalIf(token);
+}
+
+void DirectiveParser::parseIfndef(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_IFNDEF);
+ parseConditionalIf(token);
+}
+
+void DirectiveParser::parseElse(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_ELSE);
+
+ if (mConditionalStack.empty())
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ ConditionalBlock& block = mConditionalStack.back();
+ if (block.skipBlock)
+ {
+ // No diagnostics. Just skip the whole line.
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+ if (block.foundElseGroup)
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ block.foundElseGroup = true;
+ block.skipGroup = block.foundValidGroup;
+ block.foundValidGroup = true;
+
+ // Warn if there are extra tokens after #else.
+ mTokenizer->lex(token);
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
+}
+
+void DirectiveParser::parseElif(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_ELIF);
+
+ if (mConditionalStack.empty())
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ ConditionalBlock& block = mConditionalStack.back();
+ if (block.skipBlock)
+ {
+ // No diagnostics. Just skip the whole line.
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+ if (block.foundElseGroup)
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+ if (block.foundValidGroup)
+ {
+ // Do not parse the expression.
+ // Also be careful not to emit a diagnostic.
+ block.skipGroup = true;
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ int expression = parseExpressionIf(token);
+ block.skipGroup = expression == 0;
+ block.foundValidGroup = expression != 0;
+}
+
+void DirectiveParser::parseEndif(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_ENDIF);
+
+ if (mConditionalStack.empty())
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ mConditionalStack.pop_back();
+
+ // Warn if there are tokens after #endif.
+ mTokenizer->lex(token);
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
+}
+
+void DirectiveParser::parseError(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_ERROR);
+
+ std::ostringstream stream;
+ mTokenizer->lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ stream << *token;
+ mTokenizer->lex(token);
+ }
+ mDirectiveHandler->handleError(token->location, stream.str());
+}
+
+// Parses pragma of form: #pragma name[(value)].
+void DirectiveParser::parsePragma(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_PRAGMA);
+
+ enum State
+ {
+ PRAGMA_NAME,
+ LEFT_PAREN,
+ PRAGMA_VALUE,
+ RIGHT_PAREN
+ };
+
+ bool valid = true;
+ std::string name, value;
+ int state = PRAGMA_NAME;
+
+ mTokenizer->lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ switch(state++)
+ {
+ case PRAGMA_NAME:
+ name = token->text;
+ valid = valid && (token->type == Token::IDENTIFIER);
+ break;
+ case LEFT_PAREN:
+ valid = valid && (token->type == '(');
+ break;
+ case PRAGMA_VALUE:
+ value = token->text;
+ valid = valid && (token->type == Token::IDENTIFIER);
+ break;
+ case RIGHT_PAREN:
+ valid = valid && (token->type == ')');
+ break;
+ default:
+ valid = false;
+ break;
+ }
+ mTokenizer->lex(token);
+ }
+
+ valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
+ (state == LEFT_PAREN) || // Without value.
+ (state == RIGHT_PAREN + 1)); // With value.
+ if (!valid)
+ {
+ mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,
+ token->location, name);
+ }
+ else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
+ {
+ mDirectiveHandler->handlePragma(token->location, name, value);
+ }
+}
+
+void DirectiveParser::parseExtension(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_EXTENSION);
+
+ enum State
+ {
+ EXT_NAME,
+ COLON,
+ EXT_BEHAVIOR
+ };
+
+ bool valid = true;
+ std::string name, behavior;
+ int state = EXT_NAME;
+
+ mTokenizer->lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ switch (state++)
+ {
+ case EXT_NAME:
+ if (valid && (token->type != Token::IDENTIFIER))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid) name = token->text;
+ break;
+ case COLON:
+ if (valid && (token->type != ':'))
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ case EXT_BEHAVIOR:
+ if (valid && (token->type != Token::IDENTIFIER))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid) behavior = token->text;
+ break;
+ default:
+ if (valid)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ }
+ mTokenizer->lex(token);
+ }
+ if (valid && (state != EXT_BEHAVIOR + 1))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid)
+ mDirectiveHandler->handleExtension(token->location, name, behavior);
+}
+
+void DirectiveParser::parseVersion(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_VERSION);
+
+ if (mPastFirstStatement)
+ {
+ mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return;
+ }
+
+ enum State
+ {
+ VERSION_NUMBER
+ };
+
+ bool valid = true;
+ int version = 0;
+ int state = VERSION_NUMBER;
+
+ mTokenizer->lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ switch (state++)
+ {
+ case VERSION_NUMBER:
+ if (valid && (token->type != Token::CONST_INT))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid && !token->iValue(&version))
+ {
+ mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ default:
+ if (valid)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ }
+ mTokenizer->lex(token);
+ }
+ if (valid && (state != VERSION_NUMBER + 1))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid)
+ mDirectiveHandler->handleVersion(token->location, version);
+}
+
+void DirectiveParser::parseLine(Token* token)
+{
+ assert(getDirective(token) == DIRECTIVE_LINE);
+
+ enum State
+ {
+ LINE_NUMBER,
+ FILE_NUMBER
+ };
+
+ bool valid = true;
+ int line = 0, file = 0;
+ int state = LINE_NUMBER;
+
+ MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
+ macroExpander.lex(token);
+ while ((token->type != '\n') && (token->type != Token::LAST))
+ {
+ switch (state++)
+ {
+ case LINE_NUMBER:
+ if (valid && (token->type != Token::CONST_INT))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid && !token->iValue(&line))
+ {
+ mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ case FILE_NUMBER:
+ if (valid && (token->type != Token::CONST_INT))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid && !token->iValue(&file))
+ {
+ mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ default:
+ if (valid)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ valid = false;
+ }
+ break;
+ }
+ macroExpander.lex(token);
+ }
+
+ if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
+ {
+ mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,
+ token->location, token->text);
+ valid = false;
+ }
+ if (valid)
+ {
+ mTokenizer->setLineNumber(line);
+ if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
+ }
+}
+
+bool DirectiveParser::skipping() const
+{
+ if (mConditionalStack.empty()) return false;
+
+ const ConditionalBlock& block = mConditionalStack.back();
+ return block.skipBlock || block.skipGroup;
+}
+
+void DirectiveParser::parseConditionalIf(Token* token)
+{
+ ConditionalBlock block;
+ block.type = token->text;
+ block.location = token->location;
+
+ if (skipping())
+ {
+ // This conditional block is inside another conditional group
+ // which is skipped. As a consequence this whole block is skipped.
+ // Be careful not to parse the conditional expression that might
+ // emit a diagnostic.
+ skipUntilEOD(mTokenizer, token);
+ block.skipBlock = true;
+ }
+ else
+ {
+ DirectiveType directive = getDirective(token);
+
+ int expression = 0;
+ switch (directive)
+ {
+ case DIRECTIVE_IF:
+ expression = parseExpressionIf(token);
+ break;
+ case DIRECTIVE_IFDEF:
+ expression = parseExpressionIfdef(token);
+ break;
+ case DIRECTIVE_IFNDEF:
+ expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ block.skipGroup = expression == 0;
+ block.foundValidGroup = expression != 0;
+ }
+ mConditionalStack.push_back(block);
+}
+
+int DirectiveParser::parseExpressionIf(Token* token)
+{
+ assert((getDirective(token) == DIRECTIVE_IF) ||
+ (getDirective(token) == DIRECTIVE_ELIF));
+
+ DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
+ MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
+ ExpressionParser expressionParser(&macroExpander, mDiagnostics);
+
+ int expression = 0;
+ macroExpander.lex(token);
+ expressionParser.parse(token, &expression);
+
+ // Warn if there are tokens after #if expression.
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
+
+ return expression;
+}
+
+int DirectiveParser::parseExpressionIfdef(Token* token)
+{
+ assert((getDirective(token) == DIRECTIVE_IFDEF) ||
+ (getDirective(token) == DIRECTIVE_IFNDEF));
+
+ mTokenizer->lex(token);
+ if (token->type != Token::IDENTIFIER)
+ {
+ mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ return 0;
+ }
+
+ MacroSet::const_iterator iter = mMacroSet->find(token->text);
+ int expression = iter != mMacroSet->end() ? 1 : 0;
+
+ // Warn if there are tokens after #ifdef expression.
+ mTokenizer->lex(token);
+ if (!isEOD(token))
+ {
+ mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ token->location, token->text);
+ skipUntilEOD(mTokenizer, token);
+ }
+ return expression;
+}
+
+} // namespace pp
diff --git a/src/compiler/preprocessor/DirectiveParser.h b/src/compiler/preprocessor/DirectiveParser.h
new file mode 100644
index 00000000..8a7f0072
--- /dev/null
+++ b/src/compiler/preprocessor/DirectiveParser.h
@@ -0,0 +1,82 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
+#define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
+
+#include "Lexer.h"
+#include "Macro.h"
+#include "pp_utils.h"
+#include "SourceLocation.h"
+
+namespace pp
+{
+
+class Diagnostics;
+class DirectiveHandler;
+class Tokenizer;
+
+class DirectiveParser : public Lexer
+{
+ public:
+ DirectiveParser(Tokenizer* tokenizer,
+ MacroSet* macroSet,
+ Diagnostics* diagnostics,
+ DirectiveHandler* directiveHandler);
+
+ virtual void lex(Token* token);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(DirectiveParser);
+
+ void parseDirective(Token* token);
+ void parseDefine(Token* token);
+ void parseUndef(Token* token);
+ void parseIf(Token* token);
+ void parseIfdef(Token* token);
+ void parseIfndef(Token* token);
+ void parseElse(Token* token);
+ void parseElif(Token* token);
+ void parseEndif(Token* token);
+ void parseError(Token* token);
+ void parsePragma(Token* token);
+ void parseExtension(Token* token);
+ void parseVersion(Token* token);
+ void parseLine(Token* token);
+
+ bool skipping() const;
+ void parseConditionalIf(Token* token);
+ int parseExpressionIf(Token* token);
+ int parseExpressionIfdef(Token* token);
+
+ struct ConditionalBlock
+ {
+ std::string type;
+ SourceLocation location;
+ bool skipBlock;
+ bool skipGroup;
+ bool foundValidGroup;
+ bool foundElseGroup;
+
+ ConditionalBlock() :
+ skipBlock(false),
+ skipGroup(false),
+ foundValidGroup(false),
+ foundElseGroup(false)
+ {
+ }
+ };
+ bool mPastFirstStatement;
+ std::vector<ConditionalBlock> mConditionalStack;
+ Tokenizer* mTokenizer;
+ MacroSet* mMacroSet;
+ Diagnostics* mDiagnostics;
+ DirectiveHandler* mDirectiveHandler;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_
+
diff --git a/src/compiler/preprocessor/ExpressionParser.cpp b/src/compiler/preprocessor/ExpressionParser.cpp
new file mode 100644
index 00000000..67966e95
--- /dev/null
+++ b/src/compiler/preprocessor/ExpressionParser.cpp
@@ -0,0 +1,1981 @@
+/* A Bison parser, made by GNU Bison 2.7. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.7"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse ppparse
+#define yylex pplex
+#define yyerror pperror
+#define yylval pplval
+#define yychar ppchar
+#define yydebug ppdebug
+#define yynerrs ppnerrs
+
+/* Copy the first part of user declarations. */
+
+
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+#if defined(__GNUC__)
+// Triggered by the auto-generated pplval variable.
+#if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#else
+#pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065 4701)
+#endif
+
+#include "ExpressionParser.h"
+
+#include <cassert>
+#include <sstream>
+
+#include "DiagnosticsBase.h"
+#include "Lexer.h"
+#include "Token.h"
+
+#if defined(_MSC_VER)
+typedef __int64 YYSTYPE;
+#else
+#include <stdint.h>
+typedef intmax_t YYSTYPE;
+#endif // _MSC_VER
+#define YYENABLE_NLS 0
+#define YYLTYPE_IS_TRIVIAL 1
+#define YYSTYPE_IS_TRIVIAL 1
+#define YYSTYPE_IS_DECLARED 1
+
+namespace {
+struct Context
+{
+ pp::Diagnostics* diagnostics;
+ pp::Lexer* lexer;
+ pp::Token* token;
+ int* result;
+};
+} // namespace
+
+
+static int yylex(YYSTYPE* lvalp, Context* context);
+static void yyerror(Context* context, const char* reason);
+
+
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int ppdebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ TOK_CONST_INT = 258,
+ TOK_OP_OR = 259,
+ TOK_OP_AND = 260,
+ TOK_OP_NE = 261,
+ TOK_OP_EQ = 262,
+ TOK_OP_GE = 263,
+ TOK_OP_LE = 264,
+ TOK_OP_RIGHT = 265,
+ TOK_OP_LEFT = 266,
+ TOK_UNARY = 267
+ };
+#endif
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int ppparse (void *YYPARSE_PARAM);
+#else
+int ppparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int ppparse (Context *context);
+#else
+int ppparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* Copy the second part of user declarations. */
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(N) (N)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 14
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 175
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 27
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 3
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 26
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 52
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 267
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 23, 2, 2, 2, 21, 8, 2,
+ 25, 26, 19, 17, 2, 18, 2, 20, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 11, 2, 12, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 7, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 6, 2, 24, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 9, 10, 13, 14, 15, 16, 22
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 11, 15, 19, 23, 27,
+ 31, 35, 39, 43, 47, 51, 55, 59, 63, 67,
+ 71, 75, 79, 82, 85, 88, 91
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 28, 0, -1, 29, -1, 3, -1, 29, 4, 29,
+ -1, 29, 5, 29, -1, 29, 6, 29, -1, 29,
+ 7, 29, -1, 29, 8, 29, -1, 29, 9, 29,
+ -1, 29, 10, 29, -1, 29, 13, 29, -1, 29,
+ 14, 29, -1, 29, 12, 29, -1, 29, 11, 29,
+ -1, 29, 15, 29, -1, 29, 16, 29, -1, 29,
+ 18, 29, -1, 29, 17, 29, -1, 29, 21, 29,
+ -1, 29, 20, 29, -1, 29, 19, 29, -1, 23,
+ 29, -1, 24, 29, -1, 18, 29, -1, 17, 29,
+ -1, 25, 29, 26, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 91, 91, 98, 99, 102, 105, 108, 111, 114,
+ 117, 120, 123, 126, 129, 132, 135, 138, 141, 144,
+ 157, 170, 173, 176, 179, 182, 185
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "TOK_CONST_INT", "TOK_OP_OR",
+ "TOK_OP_AND", "'|'", "'^'", "'&'", "TOK_OP_NE", "TOK_OP_EQ", "'<'",
+ "'>'", "TOK_OP_GE", "TOK_OP_LE", "TOK_OP_RIGHT", "TOK_OP_LEFT", "'+'",
+ "'-'", "'*'", "'/'", "'%'", "TOK_UNARY", "'!'", "'~'", "'('", "')'",
+ "$accept", "input", "expression", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 124, 94, 38, 261,
+ 262, 60, 62, 263, 264, 265, 266, 43, 45, 42,
+ 47, 37, 267, 33, 126, 40, 41
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 27, 28, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 1, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 2, 2, 2, 2, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 3, 0, 0, 0, 0, 0, 0, 2, 25,
+ 24, 22, 23, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 26, 4, 5, 6, 7, 8, 9,
+ 10, 14, 13, 11, 12, 15, 16, 18, 17, 21,
+ 20, 19
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 7, 8
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -11
+static const yytype_int16 yypact[] =
+{
+ 46, -11, 46, 46, 46, 46, 46, 12, 68, -11,
+ -11, -11, -11, 27, -11, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, -11, 85, 101, 116, 130, 143, 154,
+ 154, -10, -10, -10, -10, 37, 37, 31, 31, -11,
+ -11, -11
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -11, -11, -2
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 9, 10, 11, 12, 13, 26, 27, 28, 29, 30,
+ 31, 32, 14, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 1,
+ 30, 31, 32, 33, 28, 29, 30, 31, 32, 0,
+ 0, 0, 0, 2, 3, 0, 0, 0, 0, 4,
+ 5, 6, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32
+};
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-11)))
+
+#define yytable_value_is_error(Yytable_value) \
+ YYID (0)
+
+static const yytype_int8 yycheck[] =
+{
+ 2, 3, 4, 5, 6, 15, 16, 17, 18, 19,
+ 20, 21, 0, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 3,
+ 19, 20, 21, 26, 17, 18, 19, 20, 21, -1,
+ -1, -1, -1, 17, 18, -1, -1, -1, -1, 23,
+ 24, 25, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 17, 18, 23, 24, 25, 28, 29, 29,
+ 29, 29, 29, 29, 0, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 26, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (context, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval, context)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, context); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, Context *context)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, context)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ Context *context;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+ YYUSE (context);
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, Context *context)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, context)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ Context *context;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, context);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, Context *context)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, context)
+ YYSTYPE *yyvsp;
+ int yyrule;
+ Context *context;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , context);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule, context); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, Context *context)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, context)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+ Context *context;
+#endif
+{
+ YYUSE (yyvaluep);
+ YYUSE (context);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (Context *context)
+#else
+int
+yyparse (context)
+ Context *context;
+#endif
+#endif
+{
+/* The lookahead symbol. */
+int yychar;
+
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+static YYSTYPE yyval_default;
+# define YY_INITIAL_VALUE(Value) = Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
+
+ /* Number of syntax errors so far. */
+ int yynerrs;
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+
+ {
+ *(context->result) = static_cast<int>((yyvsp[(1) - (1)]));
+ YYACCEPT;
+ }
+ break;
+
+ case 4:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) || (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 5:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) && (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 6:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) | (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 7:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) ^ (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 8:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) & (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 9:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) != (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 10:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) == (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 11:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) >= (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 12:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) <= (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 13:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) > (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 14:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) < (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 15:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) >> (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 16:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) << (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 17:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) - (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 18:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) + (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 19:
+
+ {
+ if ((yyvsp[(3) - (3)]) == 0) {
+ std::ostringstream stream;
+ stream << (yyvsp[(1) - (3)]) << " % " << (yyvsp[(3) - (3)]);
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ YYABORT;
+ } else {
+ (yyval) = (yyvsp[(1) - (3)]) % (yyvsp[(3) - (3)]);
+ }
+ }
+ break;
+
+ case 20:
+
+ {
+ if ((yyvsp[(3) - (3)]) == 0) {
+ std::ostringstream stream;
+ stream << (yyvsp[(1) - (3)]) << " / " << (yyvsp[(3) - (3)]);
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ YYABORT;
+ } else {
+ (yyval) = (yyvsp[(1) - (3)]) / (yyvsp[(3) - (3)]);
+ }
+ }
+ break;
+
+ case 21:
+
+ {
+ (yyval) = (yyvsp[(1) - (3)]) * (yyvsp[(3) - (3)]);
+ }
+ break;
+
+ case 22:
+
+ {
+ (yyval) = ! (yyvsp[(2) - (2)]);
+ }
+ break;
+
+ case 23:
+
+ {
+ (yyval) = ~ (yyvsp[(2) - (2)]);
+ }
+ break;
+
+ case 24:
+
+ {
+ (yyval) = - (yyvsp[(2) - (2)]);
+ }
+ break;
+
+ case 25:
+
+ {
+ (yyval) = + (yyvsp[(2) - (2)]);
+ }
+ break;
+
+ case 26:
+
+ {
+ (yyval) = (yyvsp[(2) - (3)]);
+ }
+ break;
+
+
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (context, YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (context, yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, context);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, context);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (context, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, context);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, context);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+
+
+int yylex(YYSTYPE* lvalp, Context* context)
+{
+ int type = 0;
+
+ pp::Token* token = context->token;
+ switch (token->type)
+ {
+ case pp::Token::CONST_INT:
+ {
+ unsigned int val = 0;
+ if (!token->uValue(&val))
+ {
+ context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ }
+ *lvalp = static_cast<YYSTYPE>(val);
+ type = TOK_CONST_INT;
+ break;
+ }
+ case pp::Token::OP_OR: type = TOK_OP_OR; break;
+ case pp::Token::OP_AND: type = TOK_OP_AND; break;
+ case pp::Token::OP_NE: type = TOK_OP_NE; break;
+ case pp::Token::OP_EQ: type = TOK_OP_EQ; break;
+ case pp::Token::OP_GE: type = TOK_OP_GE; break;
+ case pp::Token::OP_LE: type = TOK_OP_LE; break;
+ case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break;
+ case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break;
+ case '|': type = '|'; break;
+ case '^': type = '^'; break;
+ case '&': type = '&'; break;
+ case '>': type = '>'; break;
+ case '<': type = '<'; break;
+ case '-': type = '-'; break;
+ case '+': type = '+'; break;
+ case '%': type = '%'; break;
+ case '/': type = '/'; break;
+ case '*': type = '*'; break;
+ case '!': type = '!'; break;
+ case '~': type = '~'; break;
+ case '(': type = '('; break;
+ case ')': type = ')'; break;
+
+ default: break;
+ }
+
+ // Advance to the next token if the current one is valid.
+ if (type != 0) context->lexer->lex(token);
+
+ return type;
+}
+
+void yyerror(Context* context, const char* reason)
+{
+ context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION,
+ context->token->location,
+ reason);
+}
+
+namespace pp {
+
+ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) :
+ mLexer(lexer),
+ mDiagnostics(diagnostics)
+{
+}
+
+bool ExpressionParser::parse(Token* token, int* result)
+{
+ Context context;
+ context.diagnostics = mDiagnostics;
+ context.lexer = mLexer;
+ context.token = token;
+ context.result = result;
+ int ret = yyparse(&context);
+ switch (ret)
+ {
+ case 0:
+ case 1:
+ break;
+
+ case 2:
+ mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, "");
+ break;
+
+ default:
+ assert(false);
+ mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, "");
+ break;
+ }
+
+ return ret == 0;
+}
+
+} // namespace pp
diff --git a/src/compiler/preprocessor/ExpressionParser.h b/src/compiler/preprocessor/ExpressionParser.h
new file mode 100644
index 00000000..092d0594
--- /dev/null
+++ b/src/compiler/preprocessor/ExpressionParser.h
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
+#define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
+
+#include "pp_utils.h"
+
+namespace pp
+{
+
+class Diagnostics;
+class Lexer;
+struct Token;
+
+class ExpressionParser
+{
+ public:
+ ExpressionParser(Lexer* lexer, Diagnostics* diagnostics);
+
+ bool parse(Token* token, int* result);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(ExpressionParser);
+
+ Lexer* mLexer;
+ Diagnostics* mDiagnostics;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_
diff --git a/src/compiler/preprocessor/ExpressionParser.y b/src/compiler/preprocessor/ExpressionParser.y
new file mode 100644
index 00000000..b6d3143e
--- /dev/null
+++ b/src/compiler/preprocessor/ExpressionParser.y
@@ -0,0 +1,285 @@
+/*
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Yacc grammar for GLSL ES preprocessor expression.
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
+WHICH GENERATES THE GLSL ES preprocessor expression parser.
+*/
+
+%{
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+#if defined(__GNUC__)
+// Triggered by the auto-generated pplval variable.
+#if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#else
+#pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
+#elif defined(_MSC_VER)
+#pragma warning(disable: 4065 4701)
+#endif
+
+#include "ExpressionParser.h"
+
+#include <cassert>
+#include <sstream>
+
+#include "DiagnosticsBase.h"
+#include "Lexer.h"
+#include "Token.h"
+
+#if defined(_MSC_VER)
+typedef __int64 YYSTYPE;
+#else
+#include <stdint.h>
+typedef intmax_t YYSTYPE;
+#endif // _MSC_VER
+#define YYENABLE_NLS 0
+#define YYLTYPE_IS_TRIVIAL 1
+#define YYSTYPE_IS_TRIVIAL 1
+#define YYSTYPE_IS_DECLARED 1
+
+namespace {
+struct Context
+{
+ pp::Diagnostics* diagnostics;
+ pp::Lexer* lexer;
+ pp::Token* token;
+ int* result;
+};
+} // namespace
+%}
+
+%pure-parser
+%name-prefix="pp"
+%parse-param {Context *context}
+%lex-param {Context *context}
+
+%{
+static int yylex(YYSTYPE* lvalp, Context* context);
+static void yyerror(Context* context, const char* reason);
+%}
+
+%token TOK_CONST_INT
+%left TOK_OP_OR
+%left TOK_OP_AND
+%left '|'
+%left '^'
+%left '&'
+%left TOK_OP_EQ TOK_OP_NE
+%left '<' '>' TOK_OP_LE TOK_OP_GE
+%left TOK_OP_LEFT TOK_OP_RIGHT
+%left '+' '-'
+%left '*' '/' '%'
+%right TOK_UNARY
+
+%%
+
+input
+ : expression {
+ *(context->result) = static_cast<int>($1);
+ YYACCEPT;
+ }
+;
+
+expression
+ : TOK_CONST_INT
+ | expression TOK_OP_OR expression {
+ $$ = $1 || $3;
+ }
+ | expression TOK_OP_AND expression {
+ $$ = $1 && $3;
+ }
+ | expression '|' expression {
+ $$ = $1 | $3;
+ }
+ | expression '^' expression {
+ $$ = $1 ^ $3;
+ }
+ | expression '&' expression {
+ $$ = $1 & $3;
+ }
+ | expression TOK_OP_NE expression {
+ $$ = $1 != $3;
+ }
+ | expression TOK_OP_EQ expression {
+ $$ = $1 == $3;
+ }
+ | expression TOK_OP_GE expression {
+ $$ = $1 >= $3;
+ }
+ | expression TOK_OP_LE expression {
+ $$ = $1 <= $3;
+ }
+ | expression '>' expression {
+ $$ = $1 > $3;
+ }
+ | expression '<' expression {
+ $$ = $1 < $3;
+ }
+ | expression TOK_OP_RIGHT expression {
+ $$ = $1 >> $3;
+ }
+ | expression TOK_OP_LEFT expression {
+ $$ = $1 << $3;
+ }
+ | expression '-' expression {
+ $$ = $1 - $3;
+ }
+ | expression '+' expression {
+ $$ = $1 + $3;
+ }
+ | expression '%' expression {
+ if ($3 == 0) {
+ std::ostringstream stream;
+ stream << $1 << " % " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ YYABORT;
+ } else {
+ $$ = $1 % $3;
+ }
+ }
+ | expression '/' expression {
+ if ($3 == 0) {
+ std::ostringstream stream;
+ stream << $1 << " / " << $3;
+ std::string text = stream.str();
+ context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
+ context->token->location,
+ text.c_str());
+ YYABORT;
+ } else {
+ $$ = $1 / $3;
+ }
+ }
+ | expression '*' expression {
+ $$ = $1 * $3;
+ }
+ | '!' expression %prec TOK_UNARY {
+ $$ = ! $2;
+ }
+ | '~' expression %prec TOK_UNARY {
+ $$ = ~ $2;
+ }
+ | '-' expression %prec TOK_UNARY {
+ $$ = - $2;
+ }
+ | '+' expression %prec TOK_UNARY {
+ $$ = + $2;
+ }
+ | '(' expression ')' {
+ $$ = $2;
+ }
+;
+
+%%
+
+int yylex(YYSTYPE* lvalp, Context* context)
+{
+ int type = 0;
+
+ pp::Token* token = context->token;
+ switch (token->type)
+ {
+ case pp::Token::CONST_INT:
+ {
+ unsigned int val = 0;
+ if (!token->uValue(&val))
+ {
+ context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ }
+ *lvalp = static_cast<YYSTYPE>(val);
+ type = TOK_CONST_INT;
+ break;
+ }
+ case pp::Token::OP_OR: type = TOK_OP_OR; break;
+ case pp::Token::OP_AND: type = TOK_OP_AND; break;
+ case pp::Token::OP_NE: type = TOK_OP_NE; break;
+ case pp::Token::OP_EQ: type = TOK_OP_EQ; break;
+ case pp::Token::OP_GE: type = TOK_OP_GE; break;
+ case pp::Token::OP_LE: type = TOK_OP_LE; break;
+ case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break;
+ case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break;
+ case '|': type = '|'; break;
+ case '^': type = '^'; break;
+ case '&': type = '&'; break;
+ case '>': type = '>'; break;
+ case '<': type = '<'; break;
+ case '-': type = '-'; break;
+ case '+': type = '+'; break;
+ case '%': type = '%'; break;
+ case '/': type = '/'; break;
+ case '*': type = '*'; break;
+ case '!': type = '!'; break;
+ case '~': type = '~'; break;
+ case '(': type = '('; break;
+ case ')': type = ')'; break;
+
+ default: break;
+ }
+
+ // Advance to the next token if the current one is valid.
+ if (type != 0) context->lexer->lex(token);
+
+ return type;
+}
+
+void yyerror(Context* context, const char* reason)
+{
+ context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION,
+ context->token->location,
+ reason);
+}
+
+namespace pp {
+
+ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) :
+ mLexer(lexer),
+ mDiagnostics(diagnostics)
+{
+}
+
+bool ExpressionParser::parse(Token* token, int* result)
+{
+ Context context;
+ context.diagnostics = mDiagnostics;
+ context.lexer = mLexer;
+ context.token = token;
+ context.result = result;
+ int ret = yyparse(&context);
+ switch (ret)
+ {
+ case 0:
+ case 1:
+ break;
+
+ case 2:
+ mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, "");
+ break;
+
+ default:
+ assert(false);
+ mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, "");
+ break;
+ }
+
+ return ret == 0;
+}
+
+} // namespace pp
diff --git a/src/compiler/preprocessor/Input.cpp b/src/compiler/preprocessor/Input.cpp
new file mode 100644
index 00000000..b4d970a9
--- /dev/null
+++ b/src/compiler/preprocessor/Input.cpp
@@ -0,0 +1,54 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Input.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+
+namespace pp
+{
+
+Input::Input() : mCount(0), mString(0)
+{
+}
+
+Input::Input(size_t count, const char* const string[], const int length[]) :
+ mCount(count),
+ mString(string)
+{
+ mLength.reserve(mCount);
+ for (size_t i = 0; i < mCount; ++i)
+ {
+ int len = length ? length[i] : -1;
+ mLength.push_back(len < 0 ? std::strlen(mString[i]) : len);
+ }
+}
+
+size_t Input::read(char* buf, size_t maxSize)
+{
+ size_t nRead = 0;
+ while ((nRead < maxSize) && (mReadLoc.sIndex < mCount))
+ {
+ size_t size = mLength[mReadLoc.sIndex] - mReadLoc.cIndex;
+ size = std::min(size, maxSize);
+ std::memcpy(buf + nRead, mString[mReadLoc.sIndex] + mReadLoc.cIndex, size);
+ nRead += size;
+ mReadLoc.cIndex += size;
+
+ // Advance string if we reached the end of current string.
+ if (mReadLoc.cIndex == mLength[mReadLoc.sIndex])
+ {
+ ++mReadLoc.sIndex;
+ mReadLoc.cIndex = 0;
+ }
+ }
+ return nRead;
+}
+
+} // namespace pp
+
diff --git a/src/compiler/preprocessor/Input.h b/src/compiler/preprocessor/Input.h
new file mode 100644
index 00000000..14b7597c
--- /dev/null
+++ b/src/compiler/preprocessor/Input.h
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_INPUT_H_
+#define COMPILER_PREPROCESSOR_INPUT_H_
+
+#include <stddef.h>
+#include <vector>
+
+namespace pp
+{
+
+// Holds and reads input for Lexer.
+class Input
+{
+ public:
+ Input();
+ Input(size_t count, const char* const string[], const int length[]);
+
+ size_t count() const { return mCount; }
+ const char* string(size_t index) const { return mString[index]; }
+ size_t length(size_t index) const { return mLength[index]; }
+
+ size_t read(char* buf, size_t maxSize);
+
+ struct Location
+ {
+ size_t sIndex; // String index;
+ size_t cIndex; // Char index.
+
+ Location() : sIndex(0), cIndex(0) { }
+ };
+ const Location& readLoc() const { return mReadLoc; }
+
+ private:
+ // Input.
+ size_t mCount;
+ const char* const* mString;
+ std::vector<size_t> mLength;
+
+ Location mReadLoc;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_INPUT_H_
+
diff --git a/src/compiler/preprocessor/Lexer.cpp b/src/compiler/preprocessor/Lexer.cpp
new file mode 100644
index 00000000..7c663ee7
--- /dev/null
+++ b/src/compiler/preprocessor/Lexer.cpp
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Lexer.h"
+
+namespace pp
+{
+
+Lexer::~Lexer()
+{
+}
+
+} // namespace pp
diff --git a/src/compiler/preprocessor/Lexer.h b/src/compiler/preprocessor/Lexer.h
new file mode 100644
index 00000000..eb85cea8
--- /dev/null
+++ b/src/compiler/preprocessor/Lexer.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_LEXER_H_
+#define COMPILER_PREPROCESSOR_LEXER_H_
+
+namespace pp
+{
+
+struct Token;
+
+class Lexer
+{
+ public:
+ virtual ~Lexer();
+
+ virtual void lex(Token* token) = 0;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_LEXER_H_
+
diff --git a/src/compiler/preprocessor/Macro.cpp b/src/compiler/preprocessor/Macro.cpp
new file mode 100644
index 00000000..b2e3088e
--- /dev/null
+++ b/src/compiler/preprocessor/Macro.cpp
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Macro.h"
+
+#include "Token.h"
+
+namespace pp
+{
+
+bool Macro::equals(const Macro& other) const
+{
+ return (type == other.type) &&
+ (name == other.name) &&
+ (parameters == other.parameters) &&
+ (replacements == other.replacements);
+}
+
+} // namespace pp
+
diff --git a/src/compiler/preprocessor/Macro.h b/src/compiler/preprocessor/Macro.h
new file mode 100644
index 00000000..7ec01491
--- /dev/null
+++ b/src/compiler/preprocessor/Macro.h
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_MACRO_H_
+#define COMPILER_PREPROCESSOR_MACRO_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace pp
+{
+
+struct Token;
+
+struct Macro
+{
+ enum Type
+ {
+ kTypeObj,
+ kTypeFunc
+ };
+ typedef std::vector<std::string> Parameters;
+ typedef std::vector<Token> Replacements;
+
+ Macro() : predefined(false), disabled(false), type(kTypeObj) { }
+ bool equals(const Macro& other) const;
+
+ bool predefined;
+ mutable bool disabled;
+
+ Type type;
+ std::string name;
+ Parameters parameters;
+ Replacements replacements;
+};
+
+typedef std::map<std::string, Macro> MacroSet;
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_MACRO_H_
diff --git a/src/compiler/preprocessor/MacroExpander.cpp b/src/compiler/preprocessor/MacroExpander.cpp
new file mode 100644
index 00000000..1116c516
--- /dev/null
+++ b/src/compiler/preprocessor/MacroExpander.cpp
@@ -0,0 +1,370 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "MacroExpander.h"
+
+#include <algorithm>
+#include <sstream>
+
+#include "DiagnosticsBase.h"
+#include "Token.h"
+
+namespace pp
+{
+
+class TokenLexer : public Lexer
+{
+ public:
+ typedef std::vector<Token> TokenVector;
+
+ TokenLexer(TokenVector* tokens)
+ {
+ tokens->swap(mTokens);
+ mIter = mTokens.begin();
+ }
+
+ virtual void lex(Token* token)
+ {
+ if (mIter == mTokens.end())
+ {
+ token->reset();
+ token->type = Token::LAST;
+ }
+ else
+ {
+ *token = *mIter++;
+ }
+ }
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer);
+
+ TokenVector mTokens;
+ TokenVector::const_iterator mIter;
+};
+
+MacroExpander::MacroExpander(Lexer* lexer,
+ MacroSet* macroSet,
+ Diagnostics* diagnostics) :
+ mLexer(lexer),
+ mMacroSet(macroSet),
+ mDiagnostics(diagnostics)
+{
+}
+
+MacroExpander::~MacroExpander()
+{
+ for (std::size_t i = 0; i < mContextStack.size(); ++i)
+ {
+ delete mContextStack[i];
+ }
+}
+
+void MacroExpander::lex(Token* token)
+{
+ while (true)
+ {
+ getToken(token);
+
+ if (token->type != Token::IDENTIFIER)
+ break;
+
+ if (token->expansionDisabled())
+ break;
+
+ MacroSet::const_iterator iter = mMacroSet->find(token->text);
+ if (iter == mMacroSet->end())
+ break;
+
+ const Macro& macro = iter->second;
+ if (macro.disabled)
+ {
+ // If a particular token is not expanded, it is never expanded.
+ token->setExpansionDisabled(true);
+ break;
+ }
+ if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen())
+ {
+ // If the token immediately after the macro name is not a '(',
+ // this macro should not be expanded.
+ break;
+ }
+
+ pushMacro(macro, *token);
+ }
+}
+
+void MacroExpander::getToken(Token* token)
+{
+ if (mReserveToken.get())
+ {
+ *token = *mReserveToken;
+ mReserveToken.reset();
+ return;
+ }
+
+ // First pop all empty macro contexts.
+ while (!mContextStack.empty() && mContextStack.back()->empty())
+ {
+ popMacro();
+ }
+
+ if (!mContextStack.empty())
+ {
+ *token = mContextStack.back()->get();
+ }
+ else
+ {
+ mLexer->lex(token);
+ }
+}
+
+void MacroExpander::ungetToken(const Token& token)
+{
+ if (!mContextStack.empty())
+ {
+ MacroContext* context = mContextStack.back();
+ context->unget();
+ assert(context->replacements[context->index] == token);
+ }
+ else
+ {
+ assert(!mReserveToken.get());
+ mReserveToken.reset(new Token(token));
+ }
+}
+
+bool MacroExpander::isNextTokenLeftParen()
+{
+ Token token;
+ getToken(&token);
+
+ bool lparen = token.type == '(';
+ ungetToken(token);
+
+ return lparen;
+}
+
+bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier)
+{
+ assert(!macro.disabled);
+ assert(!identifier.expansionDisabled());
+ assert(identifier.type == Token::IDENTIFIER);
+ assert(identifier.text == macro.name);
+
+ std::vector<Token> replacements;
+ if (!expandMacro(macro, identifier, &replacements))
+ return false;
+
+ // Macro is disabled for expansion until it is popped off the stack.
+ macro.disabled = true;
+
+ MacroContext* context = new MacroContext;
+ context->macro = &macro;
+ context->replacements.swap(replacements);
+ mContextStack.push_back(context);
+ return true;
+}
+
+void MacroExpander::popMacro()
+{
+ assert(!mContextStack.empty());
+
+ MacroContext* context = mContextStack.back();
+ mContextStack.pop_back();
+
+ assert(context->empty());
+ assert(context->macro->disabled);
+ context->macro->disabled = false;
+ delete context;
+}
+
+bool MacroExpander::expandMacro(const Macro& macro,
+ const Token& identifier,
+ std::vector<Token>* replacements)
+{
+ replacements->clear();
+ if (macro.type == Macro::kTypeObj)
+ {
+ replacements->assign(macro.replacements.begin(),
+ macro.replacements.end());
+
+ if (macro.predefined)
+ {
+ static const std::string kLine = "__LINE__";
+ static const std::string kFile = "__FILE__";
+
+ assert(replacements->size() == 1);
+ Token& repl = replacements->front();
+ if (macro.name == kLine)
+ {
+ std::ostringstream stream;
+ stream << identifier.location.line;
+ repl.text = stream.str();
+ }
+ else if (macro.name == kFile)
+ {
+ std::ostringstream stream;
+ stream << identifier.location.file;
+ repl.text = stream.str();
+ }
+ }
+ }
+ else
+ {
+ assert(macro.type == Macro::kTypeFunc);
+ std::vector<MacroArg> args;
+ args.reserve(macro.parameters.size());
+ if (!collectMacroArgs(macro, identifier, &args))
+ return false;
+
+ replaceMacroParams(macro, args, replacements);
+ }
+
+ for (std::size_t i = 0; i < replacements->size(); ++i)
+ {
+ Token& repl = replacements->at(i);
+ if (i == 0)
+ {
+ // The first token in the replacement list inherits the padding
+ // properties of the identifier token.
+ repl.setAtStartOfLine(identifier.atStartOfLine());
+ repl.setHasLeadingSpace(identifier.hasLeadingSpace());
+ }
+ repl.location = identifier.location;
+ }
+ return true;
+}
+
+bool MacroExpander::collectMacroArgs(const Macro& macro,
+ const Token& identifier,
+ std::vector<MacroArg>* args)
+{
+ Token token;
+ getToken(&token);
+ assert(token.type == '(');
+
+ args->push_back(MacroArg());
+ for (int openParens = 1; openParens != 0; )
+ {
+ getToken(&token);
+
+ if (token.type == Token::LAST)
+ {
+ mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION,
+ identifier.location, identifier.text);
+ // Do not lose EOF token.
+ ungetToken(token);
+ return false;
+ }
+
+ bool isArg = false; // True if token is part of the current argument.
+ switch (token.type)
+ {
+ case '(':
+ ++openParens;
+ isArg = true;
+ break;
+ case ')':
+ --openParens;
+ isArg = openParens != 0;
+ break;
+ case ',':
+ // The individual arguments are separated by comma tokens, but
+ // the comma tokens between matching inner parentheses do not
+ // seperate arguments.
+ if (openParens == 1) args->push_back(MacroArg());
+ isArg = openParens != 1;
+ break;
+ default:
+ isArg = true;
+ break;
+ }
+ if (isArg)
+ {
+ MacroArg& arg = args->back();
+ // Initial whitespace is not part of the argument.
+ if (arg.empty()) token.setHasLeadingSpace(false);
+ arg.push_back(token);
+ }
+ }
+
+ const Macro::Parameters& params = macro.parameters;
+ // If there is only one empty argument, it is equivalent to no argument.
+ if (params.empty() && (args->size() == 1) && args->front().empty())
+ {
+ args->clear();
+ }
+ // Validate the number of arguments.
+ if (args->size() != params.size())
+ {
+ Diagnostics::ID id = args->size() < macro.parameters.size() ?
+ Diagnostics::MACRO_TOO_FEW_ARGS :
+ Diagnostics::MACRO_TOO_MANY_ARGS;
+ mDiagnostics->report(id, identifier.location, identifier.text);
+ return false;
+ }
+
+ // Pre-expand each argument before substitution.
+ // This step expands each argument individually before they are
+ // inserted into the macro body.
+ for (std::size_t i = 0; i < args->size(); ++i)
+ {
+ MacroArg& arg = args->at(i);
+ TokenLexer lexer(&arg);
+ MacroExpander expander(&lexer, mMacroSet, mDiagnostics);
+
+ arg.clear();
+ expander.lex(&token);
+ while (token.type != Token::LAST)
+ {
+ arg.push_back(token);
+ expander.lex(&token);
+ }
+ }
+ return true;
+}
+
+void MacroExpander::replaceMacroParams(const Macro& macro,
+ const std::vector<MacroArg>& args,
+ std::vector<Token>* replacements)
+{
+ for (std::size_t i = 0; i < macro.replacements.size(); ++i)
+ {
+ const Token& repl = macro.replacements[i];
+ if (repl.type != Token::IDENTIFIER)
+ {
+ replacements->push_back(repl);
+ continue;
+ }
+
+ // TODO(alokp): Optimize this.
+ // There is no need to search for macro params every time.
+ // The param index can be cached with the replacement token.
+ Macro::Parameters::const_iterator iter = std::find(
+ macro.parameters.begin(), macro.parameters.end(), repl.text);
+ if (iter == macro.parameters.end())
+ {
+ replacements->push_back(repl);
+ continue;
+ }
+
+ std::size_t iArg = std::distance(macro.parameters.begin(), iter);
+ const MacroArg& arg = args[iArg];
+ if (arg.empty())
+ {
+ continue;
+ }
+ std::size_t iRepl = replacements->size();
+ replacements->insert(replacements->end(), arg.begin(), arg.end());
+ // The replacement token inherits padding properties from
+ // macro replacement token.
+ replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace());
+ }
+}
+
+} // namespace pp
+
diff --git a/src/compiler/preprocessor/MacroExpander.h b/src/compiler/preprocessor/MacroExpander.h
new file mode 100644
index 00000000..21b67571
--- /dev/null
+++ b/src/compiler/preprocessor/MacroExpander.h
@@ -0,0 +1,75 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
+#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
+
+#include <cassert>
+#include <memory>
+#include <vector>
+
+#include "Lexer.h"
+#include "Macro.h"
+#include "pp_utils.h"
+
+namespace pp
+{
+
+class Diagnostics;
+
+class MacroExpander : public Lexer
+{
+ public:
+ MacroExpander(Lexer* lexer, MacroSet* macroSet, Diagnostics* diagnostics);
+ virtual ~MacroExpander();
+
+ virtual void lex(Token* token);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(MacroExpander);
+
+ void getToken(Token* token);
+ void ungetToken(const Token& token);
+ bool isNextTokenLeftParen();
+
+ bool pushMacro(const Macro& macro, const Token& identifier);
+ void popMacro();
+
+ bool expandMacro(const Macro& macro,
+ const Token& identifier,
+ std::vector<Token>* replacements);
+
+ typedef std::vector<Token> MacroArg;
+ bool collectMacroArgs(const Macro& macro,
+ const Token& identifier,
+ std::vector<MacroArg>* args);
+ void replaceMacroParams(const Macro& macro,
+ const std::vector<MacroArg>& args,
+ std::vector<Token>* replacements);
+
+ struct MacroContext
+ {
+ const Macro* macro;
+ std::size_t index;
+ std::vector<Token> replacements;
+
+ MacroContext() : macro(0), index(0) { }
+ bool empty() const { return index == replacements.size(); }
+ const Token& get() { return replacements[index++]; }
+ void unget() { assert(index > 0); --index; }
+ };
+
+ Lexer* mLexer;
+ MacroSet* mMacroSet;
+ Diagnostics* mDiagnostics;
+
+ std::auto_ptr<Token> mReserveToken;
+ std::vector<MacroContext*> mContextStack;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_
+
diff --git a/src/compiler/preprocessor/Preprocessor.cpp b/src/compiler/preprocessor/Preprocessor.cpp
new file mode 100644
index 00000000..5ffc6420
--- /dev/null
+++ b/src/compiler/preprocessor/Preprocessor.cpp
@@ -0,0 +1,142 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Preprocessor.h"
+
+#include <cassert>
+#include <sstream>
+
+#include "DiagnosticsBase.h"
+#include "DirectiveParser.h"
+#include "Macro.h"
+#include "MacroExpander.h"
+#include "Token.h"
+#include "Tokenizer.h"
+
+namespace pp
+{
+
+struct PreprocessorImpl
+{
+ Diagnostics* diagnostics;
+ MacroSet macroSet;
+ Tokenizer tokenizer;
+ DirectiveParser directiveParser;
+ MacroExpander macroExpander;
+
+ PreprocessorImpl(Diagnostics* diag,
+ DirectiveHandler* directiveHandler) :
+ diagnostics(diag),
+ tokenizer(diag),
+ directiveParser(&tokenizer, &macroSet, diag, directiveHandler),
+ macroExpander(&directiveParser, &macroSet, diag)
+ {
+ }
+};
+
+Preprocessor::Preprocessor(Diagnostics* diagnostics,
+ DirectiveHandler* directiveHandler)
+{
+ mImpl = new PreprocessorImpl(diagnostics, directiveHandler);
+}
+
+Preprocessor::~Preprocessor()
+{
+ delete mImpl;
+}
+
+bool Preprocessor::init(size_t count,
+ const char* const string[],
+ const int length[])
+{
+ static const int kGLSLVersion = 100;
+
+ // Add standard pre-defined macros.
+ predefineMacro("__LINE__", 0);
+ predefineMacro("__FILE__", 0);
+ predefineMacro("__VERSION__", kGLSLVersion);
+ predefineMacro("GL_ES", 1);
+
+ return mImpl->tokenizer.init(count, string, length);
+}
+
+void Preprocessor::predefineMacro(const char* name, int value)
+{
+ std::ostringstream stream;
+ stream << value;
+
+ Token token;
+ token.type = Token::CONST_INT;
+ token.text = stream.str();
+
+ Macro macro;
+ macro.predefined = true;
+ macro.type = Macro::kTypeObj;
+ macro.name = name;
+ macro.replacements.push_back(token);
+
+ mImpl->macroSet[name] = macro;
+}
+
+void Preprocessor::lex(Token* token)
+{
+ bool validToken = false;
+ while (!validToken)
+ {
+ mImpl->macroExpander.lex(token);
+ switch (token->type)
+ {
+ // We should not be returning internal preprocessing tokens.
+ // Convert preprocessing tokens to compiler tokens or report
+ // diagnostics.
+ case Token::PP_HASH:
+ assert(false);
+ break;
+ case Token::CONST_INT:
+ {
+ int val = 0;
+ if (!token->iValue(&val))
+ {
+ // Do not mark the token as invalid.
+ // Just emit the diagnostic and reset value to 0.
+ mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+ token->location, token->text);
+ token->text.assign("0");
+ }
+ validToken = true;
+ break;
+ }
+ case Token::CONST_FLOAT:
+ {
+ float val = 0;
+ if (!token->fValue(&val))
+ {
+ // Do not mark the token as invalid.
+ // Just emit the diagnostic and reset value to 0.0.
+ mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW,
+ token->location, token->text);
+ token->text.assign("0.0");
+ }
+ validToken = true;
+ break;
+ }
+ case Token::PP_NUMBER:
+ mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER,
+ token->location, token->text);
+ break;
+ case Token::PP_OTHER:
+ mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER,
+ token->location, token->text);
+ break;
+ default:
+ validToken = true;
+ break;
+ }
+ }
+}
+
+} // namespace pp
+
diff --git a/src/compiler/preprocessor/Preprocessor.h b/src/compiler/preprocessor/Preprocessor.h
new file mode 100644
index 00000000..7b70180f
--- /dev/null
+++ b/src/compiler/preprocessor/Preprocessor.h
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_PREPROCESSOR_H_
+#define COMPILER_PREPROCESSOR_PREPROCESSOR_H_
+
+#include <stddef.h>
+
+#include "pp_utils.h"
+
+namespace pp
+{
+
+class Diagnostics;
+class DirectiveHandler;
+struct PreprocessorImpl;
+struct Token;
+
+class Preprocessor
+{
+ public:
+ Preprocessor(Diagnostics* diagnostics, DirectiveHandler* directiveHandler);
+ ~Preprocessor();
+
+ // count: specifies the number of elements in the string and length arrays.
+ // string: specifies an array of pointers to strings.
+ // length: specifies an array of string lengths.
+ // If length is NULL, each string is assumed to be null terminated.
+ // If length is a value other than NULL, it points to an array containing
+ // a string length for each of the corresponding elements of string.
+ // Each element in the length array may contain the length of the
+ // corresponding string or a value less than 0 to indicate that the string
+ // is null terminated.
+ bool init(size_t count, const char* const string[], const int length[]);
+ // Adds a pre-defined macro.
+ void predefineMacro(const char* name, int value);
+
+ void lex(Token* token);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(Preprocessor);
+
+ PreprocessorImpl* mImpl;
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_
+
diff --git a/src/compiler/preprocessor/SourceLocation.h b/src/compiler/preprocessor/SourceLocation.h
new file mode 100644
index 00000000..6982613a
--- /dev/null
+++ b/src/compiler/preprocessor/SourceLocation.h
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
+#define COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
+
+namespace pp
+{
+
+struct SourceLocation
+{
+ SourceLocation() : file(0), line(0) { }
+ SourceLocation(int f, int l) : file(f), line(l) { }
+
+ bool equals(const SourceLocation& other) const
+ {
+ return (file == other.file) && (line == other.line);
+ }
+
+ int file;
+ int line;
+};
+
+inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs)
+{
+ return lhs.equals(rhs);
+}
+
+inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs)
+{
+ return !lhs.equals(rhs);
+}
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_
diff --git a/src/compiler/preprocessor/Token.cpp b/src/compiler/preprocessor/Token.cpp
new file mode 100644
index 00000000..67f50aa3
--- /dev/null
+++ b/src/compiler/preprocessor/Token.cpp
@@ -0,0 +1,83 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "Token.h"
+
+#include <cassert>
+
+#include "numeric_lex.h"
+
+namespace pp
+{
+
+void Token::reset()
+{
+ type = 0;
+ flags = 0;
+ location = SourceLocation();
+ text.clear();
+}
+
+bool Token::equals(const Token& other) const
+{
+ return (type == other.type) &&
+ (flags == other.flags) &&
+ (location == other.location) &&
+ (text == other.text);
+}
+
+void Token::setAtStartOfLine(bool start)
+{
+ if (start)
+ flags |= AT_START_OF_LINE;
+ else
+ flags &= ~AT_START_OF_LINE;
+}
+
+void Token::setHasLeadingSpace(bool space)
+{
+ if (space)
+ flags |= HAS_LEADING_SPACE;
+ else
+ flags &= ~HAS_LEADING_SPACE;
+}
+
+void Token::setExpansionDisabled(bool disable)
+{
+ if (disable)
+ flags |= EXPANSION_DISABLED;
+ else
+ flags &= ~EXPANSION_DISABLED;
+}
+
+bool Token::iValue(int* value) const
+{
+ assert(type == CONST_INT);
+ return numeric_lex_int(text, value);
+}
+
+bool Token::uValue(unsigned int* value) const
+{
+ assert(type == CONST_INT);
+ return numeric_lex_int(text, value);
+}
+
+bool Token::fValue(float* value) const
+{
+ assert(type == CONST_FLOAT);
+ return numeric_lex_float(text, value);
+}
+
+std::ostream& operator<<(std::ostream& out, const Token& token)
+{
+ if (token.hasLeadingSpace())
+ out << " ";
+
+ out << token.text;
+ return out;
+}
+
+} // namespace pp
diff --git a/src/compiler/preprocessor/Token.h b/src/compiler/preprocessor/Token.h
new file mode 100644
index 00000000..8b553aec
--- /dev/null
+++ b/src/compiler/preprocessor/Token.h
@@ -0,0 +1,106 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_TOKEN_H_
+#define COMPILER_PREPROCESSOR_TOKEN_H_
+
+#include <ostream>
+#include <string>
+
+#include "SourceLocation.h"
+
+namespace pp
+{
+
+struct Token
+{
+ enum Type
+ {
+ LAST = 0, // EOF.
+
+ IDENTIFIER = 258,
+
+ CONST_INT,
+ CONST_FLOAT,
+
+ OP_INC,
+ OP_DEC,
+ OP_LEFT,
+ OP_RIGHT,
+ OP_LE,
+ OP_GE,
+ OP_EQ,
+ OP_NE,
+ OP_AND,
+ OP_XOR,
+ OP_OR,
+ OP_ADD_ASSIGN,
+ OP_SUB_ASSIGN,
+ OP_MUL_ASSIGN,
+ OP_DIV_ASSIGN,
+ OP_MOD_ASSIGN,
+ OP_LEFT_ASSIGN,
+ OP_RIGHT_ASSIGN,
+ OP_AND_ASSIGN,
+ OP_XOR_ASSIGN,
+ OP_OR_ASSIGN,
+
+ // Preprocessing token types.
+ // These types are used by the preprocessor internally.
+ // Preprocessor clients must not depend or check for them.
+ PP_HASH,
+ PP_NUMBER,
+ PP_OTHER
+ };
+ enum Flags
+ {
+ AT_START_OF_LINE = 1 << 0,
+ HAS_LEADING_SPACE = 1 << 1,
+ EXPANSION_DISABLED = 1 << 2
+ };
+
+ Token() : type(0), flags(0) { }
+
+ void reset();
+ bool equals(const Token& other) const;
+
+ // Returns true if this is the first token on line.
+ // It disregards any leading whitespace.
+ bool atStartOfLine() const { return (flags & AT_START_OF_LINE) != 0; }
+ void setAtStartOfLine(bool start);
+
+ bool hasLeadingSpace() const { return (flags & HAS_LEADING_SPACE) != 0; }
+ void setHasLeadingSpace(bool space);
+
+ bool expansionDisabled() const { return (flags & EXPANSION_DISABLED) != 0; }
+ void setExpansionDisabled(bool disable);
+
+ // Converts text into numeric value for CONST_INT and CONST_FLOAT token.
+ // Returns false if the parsed value cannot fit into an int or float.
+ bool iValue(int* value) const;
+ bool uValue(unsigned int* value) const;
+ bool fValue(float* value) const;
+
+ int type;
+ unsigned int flags;
+ SourceLocation location;
+ std::string text;
+};
+
+inline bool operator==(const Token& lhs, const Token& rhs)
+{
+ return lhs.equals(rhs);
+}
+
+inline bool operator!=(const Token& lhs, const Token& rhs)
+{
+ return !lhs.equals(rhs);
+}
+
+extern std::ostream& operator<<(std::ostream& out, const Token& token);
+
+} // namepsace pp
+#endif // COMPILER_PREPROCESSOR_TOKEN_H_
diff --git a/src/compiler/preprocessor/Tokenizer.cpp b/src/compiler/preprocessor/Tokenizer.cpp
new file mode 100644
index 00000000..6f426780
--- /dev/null
+++ b/src/compiler/preprocessor/Tokenizer.cpp
@@ -0,0 +1,2365 @@
+#line 16 "./Tokenizer.l"
+//
+// Copyright (c) 2011-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+
+
+
+#line 13 "./Tokenizer.cpp"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+typedef uint64_t flex_uint64_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE pprestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via pprestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void pprestart (FILE *input_file ,yyscan_t yyscanner );
+void pp_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE pp_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void pp_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void pp_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void pppush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void pppop_buffer_state (yyscan_t yyscanner );
+
+static void ppensure_buffer_stack (yyscan_t yyscanner );
+static void pp_load_buffer_state (yyscan_t yyscanner );
+static void pp_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER pp_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE pp_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE pp_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE pp_scan_bytes (yyconst char *bytes,yy_size_t len ,yyscan_t yyscanner );
+
+void *ppalloc (yy_size_t ,yyscan_t yyscanner );
+void *pprealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void ppfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer pp_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ ppensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ ppensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define ppwrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (yy_size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 38
+#define YY_END_OF_BUFFER 39
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[87] =
+ { 0,
+ 0, 0, 0, 0, 39, 37, 34, 35, 35, 33,
+ 7, 33, 33, 33, 33, 33, 33, 33, 33, 9,
+ 9, 33, 33, 33, 8, 37, 33, 33, 3, 5,
+ 5, 4, 34, 35, 19, 27, 20, 30, 25, 12,
+ 23, 13, 24, 10, 2, 1, 26, 10, 9, 11,
+ 11, 11, 11, 9, 14, 16, 18, 17, 15, 8,
+ 36, 36, 31, 21, 32, 22, 3, 5, 6, 11,
+ 10, 11, 1, 10, 11, 0, 10, 9, 28, 29,
+ 0, 10, 10, 10, 10, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 2, 2, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 5, 1, 6, 1, 7, 8, 1, 9,
+ 9, 10, 11, 9, 12, 13, 14, 15, 16, 16,
+ 16, 16, 16, 16, 16, 17, 17, 9, 9, 18,
+ 19, 20, 9, 1, 21, 21, 21, 21, 22, 21,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 24, 23, 23,
+ 9, 25, 9, 26, 23, 1, 21, 21, 21, 21,
+
+ 22, 21, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 24,
+ 23, 23, 9, 27, 9, 9, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[28] =
+ { 0,
+ 1, 1, 2, 2, 1, 1, 1, 1, 1, 3,
+ 1, 1, 4, 1, 5, 5, 5, 1, 1, 1,
+ 5, 5, 5, 5, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[92] =
+ { 0,
+ 0, 0, 25, 27, 162, 163, 159, 163, 152, 132,
+ 163, 131, 24, 163, 116, 22, 26, 31, 30, 37,
+ 40, 44, 115, 46, 0, 64, 50, 15, 0, 163,
+ 124, 91, 88, 163, 163, 163, 163, 163, 163, 163,
+ 163, 163, 163, 64, 163, 0, 163, 76, 54, 58,
+ 79, 91, 91, 0, 56, 163, 163, 163, 32, 0,
+ 163, 36, 163, 163, 163, 163, 0, 163, 163, 94,
+ 0, 106, 0, 0, 113, 55, 72, 113, 163, 163,
+ 116, 101, 108, 123, 126, 163, 143, 31, 148, 153,
+ 155
+
+ } ;
+
+static yyconst flex_int16_t yy_def[92] =
+ { 0,
+ 86, 1, 87, 87, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 20, 86, 86, 86, 88, 86, 86, 86, 89, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 90, 86, 86, 20, 20,
+ 48, 51, 91, 21, 86, 86, 86, 86, 86, 88,
+ 86, 86, 86, 86, 86, 86, 89, 86, 86, 44,
+ 44, 70, 90, 48, 51, 86, 52, 91, 86, 86,
+ 86, 72, 75, 86, 86, 0, 86, 86, 86, 86,
+ 86
+
+ } ;
+
+static yyconst flex_int16_t yy_nxt[191] =
+ { 0,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 21, 22, 23, 24,
+ 25, 25, 25, 25, 26, 27, 28, 30, 31, 30,
+ 31, 37, 40, 65, 32, 60, 32, 42, 61, 45,
+ 41, 66, 38, 46, 43, 44, 44, 44, 47, 48,
+ 80, 49, 49, 50, 54, 54, 54, 51, 52, 51,
+ 53, 55, 56, 51, 58, 59, 61, 62, 63, 84,
+ 84, 84, 50, 50, 79, 64, 70, 51, 71, 71,
+ 71, 51, 86, 86, 70, 72, 70, 70, 51, 33,
+ 74, 74, 74, 51, 51, 51, 51, 75, 51, 51,
+
+ 51, 76, 76, 51, 69, 77, 77, 77, 70, 70,
+ 70, 86, 86, 51, 51, 70, 81, 81, 86, 86,
+ 82, 82, 82, 81, 81, 51, 68, 83, 83, 83,
+ 85, 85, 85, 57, 39, 51, 51, 84, 84, 84,
+ 85, 85, 85, 29, 29, 29, 29, 29, 67, 36,
+ 35, 67, 67, 73, 34, 73, 73, 73, 78, 78,
+ 33, 86, 5, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86
+ } ;
+
+static yyconst flex_int16_t yy_chk[191] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 3, 3, 4,
+ 4, 13, 16, 28, 3, 88, 4, 17, 62, 19,
+ 16, 28, 13, 19, 17, 18, 18, 18, 19, 20,
+ 59, 20, 20, 20, 21, 21, 21, 20, 20, 20,
+ 20, 22, 22, 21, 24, 24, 26, 26, 27, 76,
+ 76, 76, 50, 50, 55, 27, 44, 49, 44, 44,
+ 44, 50, 77, 77, 44, 44, 44, 44, 48, 33,
+ 48, 48, 48, 51, 51, 51, 48, 48, 48, 48,
+
+ 51, 52, 52, 53, 32, 52, 52, 52, 70, 70,
+ 70, 82, 82, 53, 53, 70, 72, 72, 83, 83,
+ 72, 72, 72, 75, 75, 78, 31, 75, 75, 75,
+ 81, 81, 81, 23, 15, 78, 78, 84, 84, 84,
+ 85, 85, 85, 87, 87, 87, 87, 87, 89, 12,
+ 10, 89, 89, 90, 9, 90, 90, 90, 91, 91,
+ 7, 5, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/*
+//
+// 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.
+//
+
+This file contains the Lex specification for GLSL ES preprocessor.
+Based on Microsoft Visual Studio 2010 Preprocessor Grammar:
+http://msdn.microsoft.com/en-us/library/2scxys89.aspx
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
+*/
+
+#include "Tokenizer.h"
+
+#include "DiagnosticsBase.h"
+#include "Token.h"
+
+#if defined(__GNUC__)
+// Triggered by the auto-generated yy_fatal_error function.
+#pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#endif
+
+typedef std::string YYSTYPE;
+typedef pp::SourceLocation YYLTYPE;
+
+// Use the unused yycolumn variable to track file (string) number.
+#define yyfileno yycolumn
+
+#define YY_USER_INIT \
+ do { \
+ yyfileno = 0; \
+ yylineno = 1; \
+ yyextra->leadingSpace = false; \
+ yyextra->lineStart = true; \
+ } while(0);
+
+#define YY_USER_ACTION \
+ do \
+ { \
+ pp::Input* input = &yyextra->input; \
+ pp::Input::Location* scanLoc = &yyextra->scanLoc; \
+ while ((scanLoc->sIndex < input->count()) && \
+ (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \
+ { \
+ scanLoc->cIndex -= input->length(scanLoc->sIndex++); \
+ ++yyfileno; yylineno = 1; \
+ } \
+ yylloc->file = yyfileno; \
+ yylloc->line = yylineno; \
+ scanLoc->cIndex += yyleng; \
+ } while(0);
+
+#define YY_INPUT(buf, result, maxSize) \
+ result = yyextra->input.read(buf, maxSize);
+
+#define INITIAL 0
+#define COMMENT 1
+
+#define YY_EXTRA_TYPE pp::Tokenizer::Context*
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ yy_size_t yy_n_chars;
+ yy_size_t yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ YYSTYPE * yylval_r;
+
+ YYLTYPE * yylloc_r;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+ /* This must go here because YYSTYPE and YYLTYPE are included
+ * from bison output in section 1.*/
+ # define yylval yyg->yylval_r
+
+ # define yylloc yyg->yylloc_r
+
+int pplex_init (yyscan_t* scanner);
+
+int pplex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int pplex_destroy (yyscan_t yyscanner );
+
+int ppget_debug (yyscan_t yyscanner );
+
+void ppset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE ppget_extra (yyscan_t yyscanner );
+
+void ppset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *ppget_in (yyscan_t yyscanner );
+
+void ppset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *ppget_out (yyscan_t yyscanner );
+
+void ppset_out (FILE * out_str ,yyscan_t yyscanner );
+
+yy_size_t ppget_leng (yyscan_t yyscanner );
+
+char *ppget_text (yyscan_t yyscanner );
+
+int ppget_lineno (yyscan_t yyscanner );
+
+void ppset_lineno (int line_number ,yyscan_t yyscanner );
+
+YYSTYPE * ppget_lval (yyscan_t yyscanner );
+
+void ppset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+ YYLTYPE *ppget_lloc (yyscan_t yyscanner );
+
+ void ppset_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int ppwrap (yyscan_t yyscanner );
+#else
+extern int ppwrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ yy_size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int pplex \
+ (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner);
+
+#define YY_DECL int pplex \
+ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Line comment */
+
+ yylval = yylval_param;
+
+ yylloc = yylloc_param;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ ppensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ pp_load_buffer_state(yyscanner );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 87 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 86 );
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+
+ YY_BREAK
+/* Block comment */
+/* Line breaks are just counted - not returned. */
+/* The comment is replaced by a single space. */
+case 2:
+YY_RULE_SETUP
+{ BEGIN(COMMENT); }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 5:
+/* rule 5 can match eol */
+YY_RULE_SETUP
+{ ++yylineno; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{
+ yyextra->leadingSpace = true;
+ BEGIN(INITIAL);
+}
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{
+ // # is only valid at start of line for preprocessor directives.
+ yylval->assign(1, yytext[0]);
+ return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER;
+}
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::IDENTIFIER;
+}
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::CONST_INT;
+}
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::CONST_FLOAT;
+}
+ YY_BREAK
+/* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */
+/* Rule to catch all invalid integers and floats. */
+case 11:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::PP_NUMBER;
+}
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_INC;
+}
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_DEC;
+}
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LEFT;
+}
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_RIGHT;
+}
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LE;
+}
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_GE;
+}
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_EQ;
+}
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_NE;
+}
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_AND;
+}
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_XOR;
+}
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_OR;
+}
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_ADD_ASSIGN;
+}
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_SUB_ASSIGN;
+}
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_MUL_ASSIGN;
+}
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_DIV_ASSIGN;
+}
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_MOD_ASSIGN;
+}
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LEFT_ASSIGN;
+}
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_RIGHT_ASSIGN;
+}
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_AND_ASSIGN;
+}
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_XOR_ASSIGN;
+}
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_OR_ASSIGN;
+}
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+{
+ yylval->assign(1, yytext[0]);
+ return yytext[0];
+}
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+{ yyextra->leadingSpace = true; }
+ YY_BREAK
+case 35:
+/* rule 35 can match eol */
+YY_RULE_SETUP
+{
+ ++yylineno;
+ yylval->assign(1, '\n');
+ return '\n';
+}
+ YY_BREAK
+case 36:
+/* rule 36 can match eol */
+YY_RULE_SETUP
+{ ++yylineno; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+{
+ yylval->assign(1, yytext[0]);
+ return pp::Token::PP_OTHER;
+}
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMENT):
+{
+ // YY_USER_ACTION is not invoked for handling EOF.
+ // Set the location for EOF token manually.
+ pp::Input* input = &yyextra->input;
+ pp::Input::Location* scanLoc = &yyextra->scanLoc;
+ yy_size_t sIndexMax = input->count() ? input->count() - 1 : 0;
+ if (scanLoc->sIndex != sIndexMax)
+ {
+ // We can only reach here if there are empty strings at the
+ // end of the input.
+ scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
+ // FIXME: this is not 64-bit clean.
+ yyfileno = static_cast<int>(sIndexMax); yylineno = 1;
+ }
+ yylloc->file = yyfileno;
+ yylloc->line = yylineno;
+ yylval->clear();
+
+ if (YY_START == COMMENT)
+ {
+ yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT,
+ pp::SourceLocation(yyfileno, yylineno),
+ "");
+ }
+ yyterminate();
+}
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * pplex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( ppwrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of pplex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = yyg->yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ pprealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ pprestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) pprealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 87 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ register int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ register char *yy_cp = yyg->yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 87 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 86);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ pprestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( ppwrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void pprestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ ppensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ pp_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ pp_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ pp_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void pp_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * pppop_buffer_state();
+ * pppush_buffer_state(new_buffer);
+ */
+ ppensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ pp_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (ppwrap()) processing, but the only time this flag
+ * is looked at is after ppwrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void pp_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE pp_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) ppalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in pp_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) ppalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in pp_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ pp_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with pp_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void pp_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ ppfree((void *) b->yy_ch_buf ,yyscanner );
+
+ ppfree((void *) b ,yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a pprestart() or at EOF.
+ */
+ static void pp_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ pp_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then pp_init_buffer was _probably_
+ * called from pprestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void pp_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ pp_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void pppush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ ppensure_buffer_stack(yyscanner);
+
+ /* This block is copied from pp_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from pp_switch_to_buffer. */
+ pp_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void pppop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ pp_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ pp_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void ppensure_buffer_stack (yyscan_t yyscanner)
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)ppalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in ppensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)pprealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in ppensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE pp_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) ppalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in pp_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ pp_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to pplex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * pp_scan_bytes() instead.
+ */
+YY_BUFFER_STATE pp_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return pp_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to pplex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE pp_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n, i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) ppalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in pp_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = pp_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in pp_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE ppget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int ppget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int ppget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *ppget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *ppget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+yy_size_t ppget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *ppget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void ppset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void ppset_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "ppset_lineno called with no buffer" , yyscanner);
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void ppset_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "ppset_column called with no buffer" , yyscanner);
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see pp_switch_to_buffer
+ */
+void ppset_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void ppset_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int ppget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void ppset_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * ppget_lval (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylval;
+}
+
+void ppset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylval = yylval_param;
+}
+
+YYLTYPE *ppget_lloc (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylloc;
+}
+
+void ppset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylloc = yylloc_param;
+}
+
+/* User-visible API */
+
+/* pplex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int pplex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) ppalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* pplex_init_extra has the same functionality as pplex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to ppalloc in
+ * the yyextra field.
+ */
+
+int pplex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+ struct yyguts_t dummy_yyguts;
+
+ ppset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) ppalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ ppset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from pplex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * pplex_init()
+ */
+ return 0;
+}
+
+/* pplex_destroy is for both reentrant and non-reentrant scanners. */
+int pplex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ pp_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ pppop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ ppfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ ppfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * pplex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ ppfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *ppalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ return (void *) malloc( size );
+}
+
+void *pprealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void ppfree (void * ptr , yyscan_t yyscanner)
+{
+ free( (char *) ptr ); /* see pprealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+namespace pp {
+
+// TODO(alokp): Maximum token length should ideally be specified by
+// the preprocessor client, i.e., the compiler.
+const size_t Tokenizer::kMaxTokenLength = 256;
+
+Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0)
+{
+ mContext.diagnostics = diagnostics;
+}
+
+Tokenizer::~Tokenizer()
+{
+ destroyScanner();
+}
+
+bool Tokenizer::init(size_t count, const char* const string[], const int length[])
+{
+ if ((count > 0) && (string == 0)) return false;
+
+ mContext.input = Input(count, string, length);
+ return initScanner();
+}
+
+void Tokenizer::setFileNumber(int file)
+{
+ // We use column number as file number.
+ // See macro yyfileno.
+ ppset_column(file,mHandle);
+}
+
+void Tokenizer::setLineNumber(int line)
+{
+ ppset_lineno(line,mHandle);
+}
+
+void Tokenizer::lex(Token* token)
+{
+ token->type = pplex(&token->text,&token->location,mHandle);
+ if (token->text.size() > kMaxTokenLength)
+ {
+ mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG,
+ token->location, token->text);
+ token->text.erase(kMaxTokenLength);
+ }
+
+ token->flags = 0;
+
+ token->setAtStartOfLine(mContext.lineStart);
+ mContext.lineStart = token->type == '\n';
+
+ token->setHasLeadingSpace(mContext.leadingSpace);
+ mContext.leadingSpace = false;
+}
+
+bool Tokenizer::initScanner()
+{
+ if ((mHandle == NULL) && pplex_init_extra(&mContext,&mHandle))
+ return false;
+
+ pprestart(0,mHandle);
+ return true;
+}
+
+void Tokenizer::destroyScanner()
+{
+ if (mHandle == NULL)
+ return;
+
+ pplex_destroy(mHandle);
+ mHandle = NULL;
+}
+
+} // namespace pp
+
diff --git a/src/compiler/preprocessor/Tokenizer.h b/src/compiler/preprocessor/Tokenizer.h
new file mode 100644
index 00000000..7a6fa87b
--- /dev/null
+++ b/src/compiler/preprocessor/Tokenizer.h
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_PREPROCESSOR_TOKENIZER_H_
+#define COMPILER_PREPROCESSOR_TOKENIZER_H_
+
+#include "Input.h"
+#include "Lexer.h"
+#include "pp_utils.h"
+
+namespace pp
+{
+
+class Diagnostics;
+
+class Tokenizer : public Lexer
+{
+ public:
+ struct Context
+ {
+ Diagnostics* diagnostics;
+
+ Input input;
+ // The location where yytext points to. Token location should track
+ // scanLoc instead of Input::mReadLoc because they may not be the same
+ // if text is buffered up in the scanner input buffer.
+ Input::Location scanLoc;
+
+ bool leadingSpace;
+ bool lineStart;
+ };
+ static const std::size_t kMaxTokenLength;
+
+ Tokenizer(Diagnostics* diagnostics);
+ ~Tokenizer();
+
+ bool init(size_t count, const char* const string[], const int length[]);
+
+ void setFileNumber(int file);
+ void setLineNumber(int line);
+
+ virtual void lex(Token* token);
+
+ private:
+ PP_DISALLOW_COPY_AND_ASSIGN(Tokenizer);
+ bool initScanner();
+ void destroyScanner();
+
+ void* mHandle; // Scanner handle.
+ Context mContext; // Scanner extra.
+};
+
+} // namespace pp
+#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_
+
diff --git a/src/compiler/preprocessor/Tokenizer.l b/src/compiler/preprocessor/Tokenizer.l
new file mode 100644
index 00000000..fc81d84f
--- /dev/null
+++ b/src/compiler/preprocessor/Tokenizer.l
@@ -0,0 +1,342 @@
+/*
+//
+// 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.
+//
+
+This file contains the Lex specification for GLSL ES preprocessor.
+Based on Microsoft Visual Studio 2010 Preprocessor Grammar:
+http://msdn.microsoft.com/en-us/library/2scxys89.aspx
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh.
+*/
+
+%top{
+//
+// Copyright (c) 2011-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
+}
+
+%{
+#include "Tokenizer.h"
+
+#include "DiagnosticsBase.h"
+#include "Token.h"
+
+#if defined(__GNUC__)
+// Triggered by the auto-generated yy_fatal_error function.
+#pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#endif
+
+typedef std::string YYSTYPE;
+typedef pp::SourceLocation YYLTYPE;
+
+// Use the unused yycolumn variable to track file (string) number.
+#define yyfileno yycolumn
+
+#define YY_USER_INIT \
+ do { \
+ yyfileno = 0; \
+ yylineno = 1; \
+ yyextra->leadingSpace = false; \
+ yyextra->lineStart = true; \
+ } while(0);
+
+#define YY_USER_ACTION \
+ do \
+ { \
+ pp::Input* input = &yyextra->input; \
+ pp::Input::Location* scanLoc = &yyextra->scanLoc; \
+ while ((scanLoc->sIndex < input->count()) && \
+ (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \
+ { \
+ scanLoc->cIndex -= input->length(scanLoc->sIndex++); \
+ ++yyfileno; yylineno = 1; \
+ } \
+ yylloc->file = yyfileno; \
+ yylloc->line = yylineno; \
+ scanLoc->cIndex += yyleng; \
+ } while(0);
+
+#define YY_INPUT(buf, result, maxSize) \
+ result = yyextra->input.read(buf, maxSize);
+
+%}
+
+%option noyywrap nounput never-interactive
+%option reentrant bison-bridge bison-locations
+%option prefix="pp"
+%option extra-type="pp::Tokenizer::Context*"
+%x COMMENT
+
+NEWLINE \n|\r|\r\n
+IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
+PUNCTUATOR [][<>(){}.+-/*%^|&~=!:;,?]
+
+DECIMAL_CONSTANT [1-9][0-9]*
+OCTAL_CONSTANT 0[0-7]*
+HEXADECIMAL_CONSTANT 0[xX][0-9a-fA-F]+
+
+DIGIT [0-9]
+EXPONENT_PART [eE][+-]?{DIGIT}+
+FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".")
+
+%%
+
+ /* Line comment */
+"//"[^\r\n]*
+
+ /* Block comment */
+ /* Line breaks are just counted - not returned. */
+ /* The comment is replaced by a single space. */
+"/*" { BEGIN(COMMENT); }
+<COMMENT>[^*\r\n]+
+<COMMENT>"*"
+<COMMENT>{NEWLINE} { ++yylineno; }
+<COMMENT>"*/" {
+ yyextra->leadingSpace = true;
+ BEGIN(INITIAL);
+}
+
+# {
+ // # is only valid at start of line for preprocessor directives.
+ yylval->assign(1, yytext[0]);
+ return yyextra->lineStart ? pp::Token::PP_HASH : pp::Token::PP_OTHER;
+}
+
+{IDENTIFIER} {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::IDENTIFIER;
+}
+
+{DECIMAL_CONSTANT}|{OCTAL_CONSTANT}|{HEXADECIMAL_CONSTANT} {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::CONST_INT;
+}
+
+({DIGIT}+{EXPONENT_PART})|({FRACTIONAL_CONSTANT}{EXPONENT_PART}?) {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::CONST_FLOAT;
+}
+
+ /* Anything that starts with a {DIGIT} or .{DIGIT} must be a number. */
+ /* Rule to catch all invalid integers and floats. */
+({DIGIT}+[_a-zA-Z0-9.]*)|("."{DIGIT}+[_a-zA-Z0-9.]*) {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::PP_NUMBER;
+}
+
+"++" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_INC;
+}
+"--" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_DEC;
+}
+"<<" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LEFT;
+}
+">>" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_RIGHT;
+}
+"<=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LE;
+}
+">=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_GE;
+}
+"==" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_EQ;
+}
+"!=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_NE;
+}
+"&&" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_AND;
+}
+"^^" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_XOR;
+}
+"||" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_OR;
+}
+"+=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_ADD_ASSIGN;
+}
+"-=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_SUB_ASSIGN;
+}
+"*=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_MUL_ASSIGN;
+}
+"/=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_DIV_ASSIGN;
+}
+"%=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_MOD_ASSIGN;
+}
+"<<=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_LEFT_ASSIGN;
+}
+">>=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_RIGHT_ASSIGN;
+}
+"&=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_AND_ASSIGN;
+}
+"^=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_XOR_ASSIGN;
+}
+"|=" {
+ yylval->assign(yytext, yyleng);
+ return pp::Token::OP_OR_ASSIGN;
+}
+
+{PUNCTUATOR} {
+ yylval->assign(1, yytext[0]);
+ return yytext[0];
+}
+
+[ \t\v\f]+ { yyextra->leadingSpace = true; }
+
+{NEWLINE} {
+ ++yylineno;
+ yylval->assign(1, '\n');
+ return '\n';
+}
+
+\\{NEWLINE} { ++yylineno; }
+
+. {
+ yylval->assign(1, yytext[0]);
+ return pp::Token::PP_OTHER;
+}
+
+<*><<EOF>> {
+ // YY_USER_ACTION is not invoked for handling EOF.
+ // Set the location for EOF token manually.
+ pp::Input* input = &yyextra->input;
+ pp::Input::Location* scanLoc = &yyextra->scanLoc;
+ yy_size_t sIndexMax = input->count() ? input->count() - 1 : 0;
+ if (scanLoc->sIndex != sIndexMax)
+ {
+ // We can only reach here if there are empty strings at the
+ // end of the input.
+ scanLoc->sIndex = sIndexMax; scanLoc->cIndex = 0;
+ // FIXME: this is not 64-bit clean.
+ yyfileno = static_cast<int>(sIndexMax); yylineno = 1;
+ }
+ yylloc->file = yyfileno;
+ yylloc->line = yylineno;
+ yylval->clear();
+
+ if (YY_START == COMMENT)
+ {
+ yyextra->diagnostics->report(pp::Diagnostics::EOF_IN_COMMENT,
+ pp::SourceLocation(yyfileno, yylineno),
+ "");
+ }
+ yyterminate();
+}
+
+%%
+
+namespace pp {
+
+// TODO(alokp): Maximum token length should ideally be specified by
+// the preprocessor client, i.e., the compiler.
+const size_t Tokenizer::kMaxTokenLength = 256;
+
+Tokenizer::Tokenizer(Diagnostics* diagnostics) : mHandle(0)
+{
+ mContext.diagnostics = diagnostics;
+}
+
+Tokenizer::~Tokenizer()
+{
+ destroyScanner();
+}
+
+bool Tokenizer::init(size_t count, const char* const string[], const int length[])
+{
+ if ((count > 0) && (string == 0)) return false;
+
+ mContext.input = Input(count, string, length);
+ return initScanner();
+}
+
+void Tokenizer::setFileNumber(int file)
+{
+ // We use column number as file number.
+ // See macro yyfileno.
+ yyset_column(file, mHandle);
+}
+
+void Tokenizer::setLineNumber(int line)
+{
+ yyset_lineno(line, mHandle);
+}
+
+void Tokenizer::lex(Token* token)
+{
+ token->type = yylex(&token->text, &token->location, mHandle);
+ if (token->text.size() > kMaxTokenLength)
+ {
+ mContext.diagnostics->report(Diagnostics::TOKEN_TOO_LONG,
+ token->location, token->text);
+ token->text.erase(kMaxTokenLength);
+ }
+
+ token->flags = 0;
+
+ token->setAtStartOfLine(mContext.lineStart);
+ mContext.lineStart = token->type == '\n';
+
+ token->setHasLeadingSpace(mContext.leadingSpace);
+ mContext.leadingSpace = false;
+}
+
+bool Tokenizer::initScanner()
+{
+ if ((mHandle == NULL) && yylex_init_extra(&mContext, &mHandle))
+ return false;
+
+ yyrestart(0, mHandle);
+ return true;
+}
+
+void Tokenizer::destroyScanner()
+{
+ if (mHandle == NULL)
+ return;
+
+ yylex_destroy(mHandle);
+ mHandle = NULL;
+}
+
+} // namespace pp
+
diff --git a/src/compiler/preprocessor/generate_parser.sh b/src/compiler/preprocessor/generate_parser.sh
new file mode 100755
index 00000000..03285872
--- /dev/null
+++ b/src/compiler/preprocessor/generate_parser.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Generates various components of GLSL ES preprocessor.
+
+run_flex()
+{
+input_file=$script_dir/$1
+output_source=$script_dir/$2
+flex --noline --nounistd --outfile=$output_source $input_file
+}
+
+run_bison()
+{
+input_file=$script_dir/$1
+output_source=$script_dir/$2
+bison --no-lines --skeleton=yacc.c --output=$output_source $input_file
+}
+
+script_dir=$(dirname $0)
+
+# Generate preprocessor
+run_flex Tokenizer.l Tokenizer.cpp
+run_bison ExpressionParser.y ExpressionParser.cpp
+patch --silent --forward < 64bit-tokenizer-safety.patch
diff --git a/src/compiler/preprocessor/length_limits.h b/src/compiler/preprocessor/length_limits.h
new file mode 100644
index 00000000..4f1f7131
--- /dev/null
+++ b/src/compiler/preprocessor/length_limits.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// length_limits.h
+//
+
+#if !defined(__LENGTH_LIMITS_H)
+#define __LENGTH_LIMITS_H 1
+
+// These constants are factored out from the rest of the headers to
+// make it easier to reference them from the compiler sources.
+
+// These lengths do not include the NULL terminator.
+#define MAX_SYMBOL_NAME_LEN 256
+#define MAX_STRING_LEN 511
+
+#endif // !(defined(__LENGTH_LIMITS_H)
diff --git a/src/compiler/preprocessor/numeric_lex.h b/src/compiler/preprocessor/numeric_lex.h
new file mode 100644
index 00000000..b04125d2
--- /dev/null
+++ b/src/compiler/preprocessor/numeric_lex.h
@@ -0,0 +1,61 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// numeric_lex.h: Functions to extract numeric values from string.
+
+#ifndef COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
+#define COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
+
+#include <sstream>
+
+namespace pp {
+
+inline std::ios::fmtflags numeric_base_int(const std::string& str)
+{
+ if ((str.size() >= 2) &&
+ (str[0] == '0') &&
+ (str[1] == 'x' || str[1] == 'X'))
+ {
+ return std::ios::hex;
+ }
+ else if ((str.size() >= 1) && (str[0] == '0'))
+ {
+ return std::ios::oct;
+ }
+ return std::ios::dec;
+}
+
+// The following functions parse the given string to extract a numerical
+// value of the given type. These functions assume that the string is
+// of the correct form. They can only fail if the parsed value is too big,
+// in which case false is returned.
+
+template<typename IntType>
+bool numeric_lex_int(const std::string& str, IntType* value)
+{
+ std::istringstream stream(str);
+ // This should not be necessary, but MSVS has a buggy implementation.
+ // It returns incorrect results if the base is not specified.
+ stream.setf(numeric_base_int(str), std::ios::basefield);
+
+ stream >> (*value);
+ return !stream.fail();
+}
+
+template<typename FloatType>
+bool numeric_lex_float(const std::string& str, FloatType* value)
+{
+ std::istringstream stream(str);
+ // Force "C" locale so that decimal character is always '.', and
+ // not dependent on the current locale.
+ stream.imbue(std::locale::classic());
+
+ stream >> (*value);
+ return !stream.fail();
+}
+
+} // namespace pp.
+#endif // COMPILER_PREPROCESSOR_NUMERIC_LEX_H_
diff --git a/src/compiler/preprocessor/pp_utils.h b/src/compiler/preprocessor/pp_utils.h
new file mode 100644
index 00000000..17164ea8
--- /dev/null
+++ b/src/compiler/preprocessor/pp_utils.h
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// pp_utils.h: Common preprocessor utilities
+
+#ifndef COMPILER_PREPROCESSOR_PPUTILS_H_
+#define COMPILER_PREPROCESSOR_PPUTILS_H_
+
+// A macro to disallow the copy constructor and operator= functions
+// This must be used in the private: declarations for a class.
+#define PP_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+#endif // COMPILER_PREPROCESSOR_PPUTILS_H_
diff --git a/src/compiler/preprocessor/preprocessor.vcxproj b/src/compiler/preprocessor/preprocessor.vcxproj
new file mode 100644
index 00000000..ca8530b5
--- /dev/null
+++ b/src/compiler/preprocessor/preprocessor.vcxproj
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{FBE32DF3-0FB0-4F2F-A424-2C21BD7BC325}</ProjectGuid>
+ <RootNamespace>preprocessor</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;4718;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;4718;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;4718;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="DiagnosticsBase.cpp" />
+ <ClCompile Include="DirectiveHandlerBase.cpp" />
+ <ClCompile Include="DirectiveParser.cpp" />
+ <ClCompile Include="ExpressionParser.cpp" />
+ <ClCompile Include="Input.cpp" />
+ <ClCompile Include="Lexer.cpp" />
+ <ClCompile Include="Macro.cpp" />
+ <ClCompile Include="MacroExpander.cpp" />
+ <ClCompile Include="Preprocessor.cpp" />
+ <ClCompile Include="Token.cpp" />
+ <ClCompile Include="Tokenizer.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="length_limits.h" />
+ <ClInclude Include="DiagnosticsBase.h" />
+ <ClInclude Include="DirectiveHandlerBase.h" />
+ <ClInclude Include="DirectiveParser.h" />
+ <ClInclude Include="ExpressionParser.h" />
+ <ClInclude Include="Input.h" />
+ <ClInclude Include="Lexer.h" />
+ <ClInclude Include="Macro.h" />
+ <ClInclude Include="MacroExpander.h" />
+ <ClInclude Include="numeric_lex.h" />
+ <ClInclude Include="pp_utils.h" />
+ <ClInclude Include="Preprocessor.h" />
+ <ClInclude Include="SourceLocation.h" />
+ <ClInclude Include="Token.h" />
+ <ClInclude Include="Tokenizer.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Tokenizer.l" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/compiler/preprocessor/preprocessor.vcxproj.filters b/src/compiler/preprocessor/preprocessor.vcxproj.filters
new file mode 100644
index 00000000..4ac202f4
--- /dev/null
+++ b/src/compiler/preprocessor/preprocessor.vcxproj.filters
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="DirectiveParser.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ExpressionParser.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Input.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Lexer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Macro.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="MacroExpander.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Preprocessor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Token.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Tokenizer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DiagnosticsBase.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DirectiveHandlerBase.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="DirectiveParser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ExpressionParser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Input.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Lexer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Macro.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="MacroExpander.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="numeric_lex.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="pp_utils.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Preprocessor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SourceLocation.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Token.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Tokenizer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="length_limits.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="DiagnosticsBase.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="DirectiveHandlerBase.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Tokenizer.l">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/compiler/timing/RestrictFragmentShaderTiming.cpp b/src/compiler/timing/RestrictFragmentShaderTiming.cpp
new file mode 100644
index 00000000..538b731b
--- /dev/null
+++ b/src/compiler/timing/RestrictFragmentShaderTiming.cpp
@@ -0,0 +1,127 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/InfoSink.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/depgraph/DependencyGraphOutput.h"
+#include "compiler/timing/RestrictFragmentShaderTiming.h"
+
+RestrictFragmentShaderTiming::RestrictFragmentShaderTiming(TInfoSinkBase& sink)
+ : mSink(sink)
+ , mNumErrors(0)
+{
+ // Sampling ops found only in fragment shaders.
+ mSamplingOps.insert("texture2D(s21;vf2;f1;");
+ mSamplingOps.insert("texture2DProj(s21;vf3;f1;");
+ mSamplingOps.insert("texture2DProj(s21;vf4;f1;");
+ mSamplingOps.insert("textureCube(sC1;vf3;f1;");
+ // Sampling ops found in both vertex and fragment shaders.
+ mSamplingOps.insert("texture2D(s21;vf2;");
+ mSamplingOps.insert("texture2DProj(s21;vf3;");
+ mSamplingOps.insert("texture2DProj(s21;vf4;");
+ mSamplingOps.insert("textureCube(sC1;vf3;");
+ // Sampling ops provided by OES_EGL_image_external.
+ mSamplingOps.insert("texture2D(1;vf2;");
+ mSamplingOps.insert("texture2DProj(1;vf3;");
+ mSamplingOps.insert("texture2DProj(1;vf4;");
+ // Sampling ops provided by ARB_texture_rectangle.
+ mSamplingOps.insert("texture2DRect(1;vf2;");
+ mSamplingOps.insert("texture2DRectProj(1;vf3;");
+ mSamplingOps.insert("texture2DRectProj(1;vf4;");
+}
+
+// FIXME(mvujovic): We do not know if the execution time of built-in operations like sin, pow, etc.
+// can vary based on the value of the input arguments. If so, we should restrict those as well.
+void RestrictFragmentShaderTiming::enforceRestrictions(const TDependencyGraph& graph)
+{
+ mNumErrors = 0;
+
+ // FIXME(mvujovic): The dependency graph does not support user defined function calls right now,
+ // so we generate errors for them.
+ validateUserDefinedFunctionCallUsage(graph);
+
+ // Starting from each sampler, traverse the dependency graph and generate an error each time we
+ // hit a node where sampler dependent values are not allowed.
+ for (TGraphSymbolVector::const_iterator iter = graph.beginSamplerSymbols();
+ iter != graph.endSamplerSymbols();
+ ++iter)
+ {
+ TGraphSymbol* samplerSymbol = *iter;
+ clearVisited();
+ samplerSymbol->traverse(this);
+ }
+}
+
+void RestrictFragmentShaderTiming::validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph)
+{
+ for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
+ iter != graph.endUserDefinedFunctionCalls();
+ ++iter)
+ {
+ TGraphFunctionCall* functionCall = *iter;
+ beginError(functionCall->getIntermFunctionCall());
+ mSink << "A call to a user defined function is not permitted.\n";
+ }
+}
+
+void RestrictFragmentShaderTiming::beginError(const TIntermNode* node)
+{
+ ++mNumErrors;
+ mSink.prefix(EPrefixError);
+ mSink.location(node->getLine());
+}
+
+bool RestrictFragmentShaderTiming::isSamplingOp(const TIntermAggregate* intermFunctionCall) const
+{
+ return !intermFunctionCall->isUserDefined() &&
+ mSamplingOps.find(intermFunctionCall->getName()) != mSamplingOps.end();
+}
+
+void RestrictFragmentShaderTiming::visitArgument(TGraphArgument* parameter)
+{
+ // Texture cache access time might leak sensitive information.
+ // Thus, we restrict sampler dependent values from affecting the coordinate or LOD bias of a
+ // sampling operation.
+ if (isSamplingOp(parameter->getIntermFunctionCall())) {
+ switch (parameter->getArgumentNumber()) {
+ case 1:
+ // Second argument (coord)
+ beginError(parameter->getIntermFunctionCall());
+ mSink << "An expression dependent on a sampler is not permitted to be the"
+ << " coordinate argument of a sampling operation.\n";
+ break;
+ case 2:
+ // Third argument (bias)
+ beginError(parameter->getIntermFunctionCall());
+ mSink << "An expression dependent on a sampler is not permitted to be the"
+ << " bias argument of a sampling operation.\n";
+ break;
+ default:
+ // First argument (sampler)
+ break;
+ }
+ }
+}
+
+void RestrictFragmentShaderTiming::visitSelection(TGraphSelection* selection)
+{
+ beginError(selection->getIntermSelection());
+ mSink << "An expression dependent on a sampler is not permitted in a conditional statement.\n";
+}
+
+void RestrictFragmentShaderTiming::visitLoop(TGraphLoop* loop)
+{
+ beginError(loop->getIntermLoop());
+ mSink << "An expression dependent on a sampler is not permitted in a loop condition.\n";
+}
+
+void RestrictFragmentShaderTiming::visitLogicalOp(TGraphLogicalOp* logicalOp)
+{
+ beginError(logicalOp->getIntermLogicalOp());
+ mSink << "An expression dependent on a sampler is not permitted on the left hand side of a logical "
+ << logicalOp->getOpString()
+ << " operator.\n";
+}
diff --git a/src/compiler/timing/RestrictFragmentShaderTiming.h b/src/compiler/timing/RestrictFragmentShaderTiming.h
new file mode 100644
index 00000000..899165ca
--- /dev/null
+++ b/src/compiler/timing/RestrictFragmentShaderTiming.h
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
+#define COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/intermediate.h"
+#include "compiler/depgraph/DependencyGraph.h"
+
+class TInfoSinkBase;
+
+class RestrictFragmentShaderTiming : TDependencyGraphTraverser {
+public:
+ RestrictFragmentShaderTiming(TInfoSinkBase& sink);
+ void enforceRestrictions(const TDependencyGraph& graph);
+ int numErrors() const { return mNumErrors; }
+
+ virtual void visitArgument(TGraphArgument* parameter);
+ virtual void visitSelection(TGraphSelection* selection);
+ virtual void visitLoop(TGraphLoop* loop);
+ virtual void visitLogicalOp(TGraphLogicalOp* logicalOp);
+
+private:
+ void beginError(const TIntermNode* node);
+ void validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph);
+ bool isSamplingOp(const TIntermAggregate* intermFunctionCall) const;
+
+ TInfoSinkBase& mSink;
+ int mNumErrors;
+
+ typedef std::set<TString> StringSet;
+ StringSet mSamplingOps;
+};
+
+#endif // COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_
diff --git a/src/compiler/timing/RestrictVertexShaderTiming.cpp b/src/compiler/timing/RestrictVertexShaderTiming.cpp
new file mode 100644
index 00000000..355eb62d
--- /dev/null
+++ b/src/compiler/timing/RestrictVertexShaderTiming.cpp
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/timing/RestrictVertexShaderTiming.h"
+
+void RestrictVertexShaderTiming::visitSymbol(TIntermSymbol* node)
+{
+ if (IsSampler(node->getBasicType())) {
+ ++mNumErrors;
+ mSink.message(EPrefixError,
+ node->getLine(),
+ "Samplers are not permitted in vertex shaders");
+ }
+}
diff --git a/src/compiler/timing/RestrictVertexShaderTiming.h b/src/compiler/timing/RestrictVertexShaderTiming.h
new file mode 100644
index 00000000..19a05fa6
--- /dev/null
+++ b/src/compiler/timing/RestrictVertexShaderTiming.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
+#define COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/intermediate.h"
+#include "compiler/InfoSink.h"
+
+class TInfoSinkBase;
+
+class RestrictVertexShaderTiming : public TIntermTraverser {
+public:
+ RestrictVertexShaderTiming(TInfoSinkBase& sink)
+ : TIntermTraverser(true, false, false)
+ , mSink(sink)
+ , mNumErrors(0) {}
+
+ void enforceRestrictions(TIntermNode* root) { root->traverse(this); }
+ int numErrors() { return mNumErrors; }
+
+ virtual void visitSymbol(TIntermSymbol*);
+private:
+ TInfoSinkBase& mSink;
+ int mNumErrors;
+};
+
+#endif // COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_
diff --git a/src/compiler/translator_common.vcxproj b/src/compiler/translator_common.vcxproj
new file mode 100644
index 00000000..38000943
--- /dev/null
+++ b/src/compiler/translator_common.vcxproj
@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}</ProjectGuid>
+ <RootNamespace>compiler</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\common\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\common\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)../;$(ProjectDir)../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;4718;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)../;$(ProjectDir)../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4267;4512;4702;4718;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)../;$(ProjectDir)../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;4718;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)../;$(ProjectDir)../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4267;4512;4702;4718;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="BuiltInFunctionEmulator.cpp" />
+ <ClCompile Include="Compiler.cpp" />
+ <ClCompile Include="debug.cpp" />
+ <ClCompile Include="DetectCallDepth.cpp" />
+ <ClCompile Include="Diagnostics.cpp" />
+ <ClCompile Include="DirectiveHandler.cpp" />
+ <ClCompile Include="ForLoopUnroll.cpp" />
+ <ClCompile Include="InfoSink.cpp" />
+ <ClCompile Include="Initialize.cpp" />
+ <ClCompile Include="InitializeDll.cpp" />
+ <ClCompile Include="InitializeParseContext.cpp" />
+ <ClCompile Include="Intermediate.cpp" />
+ <ClCompile Include="intermOut.cpp" />
+ <ClCompile Include="IntermTraverse.cpp" />
+ <ClCompile Include="MapLongVariableNames.cpp" />
+ <ClCompile Include="ossource_win.cpp" />
+ <ClCompile Include="parseConst.cpp" />
+ <ClCompile Include="ParseHelper.cpp" />
+ <ClCompile Include="PoolAlloc.cpp" />
+ <ClCompile Include="QualifierAlive.cpp" />
+ <ClCompile Include="RemoveTree.cpp" />
+ <ClCompile Include="ShaderLang.cpp" />
+ <ClCompile Include="SymbolTable.cpp" />
+ <ClCompile Include="util.cpp" />
+ <ClCompile Include="ValidateLimitations.cpp" />
+ <ClCompile Include="VariableInfo.cpp" />
+ <ClCompile Include="VariablePacker.cpp" />
+ <ClCompile Include="glslang_lex.cpp" />
+ <ClCompile Include="glslang_tab.cpp" />
+ <ClCompile Include="depgraph\DependencyGraph.cpp" />
+ <ClCompile Include="depgraph\DependencyGraphBuilder.cpp" />
+ <ClCompile Include="depgraph\DependencyGraphOutput.cpp" />
+ <ClCompile Include="depgraph\DependencyGraphTraverse.cpp" />
+ <ClCompile Include="timing\RestrictFragmentShaderTiming.cpp" />
+ <ClCompile Include="timing\RestrictVertexShaderTiming.cpp" />
+ <ClCompile Include="..\third_party\compiler\ArrayBoundsClamper.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="glslang.l">
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ </Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ </Command>
+ <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalInputs)</AdditionalInputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Outputs)</Outputs>
+ </CustomBuild>
+ <CustomBuild Include="glslang.y">
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ </Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Outputs)</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ </Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ </Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Outputs)</Outputs>
+ </CustomBuild>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="BaseTypes.h" />
+ <ClInclude Include="BuiltInFunctionEmulator.h" />
+ <ClInclude Include="Common.h" />
+ <ClInclude Include="ConstantUnion.h" />
+ <ClInclude Include="debug.h" />
+ <ClInclude Include="DetectCallDepth.h" />
+ <ClInclude Include="Diagnostics.h" />
+ <ClInclude Include="DirectiveHandler.h" />
+ <ClInclude Include="ForLoopUnroll.h" />
+ <ClInclude Include="HashNames.h" />
+ <ClInclude Include="InfoSink.h" />
+ <ClInclude Include="Initialize.h" />
+ <ClInclude Include="InitializeDll.h" />
+ <ClInclude Include="InitializeGlobals.h" />
+ <ClInclude Include="InitializeParseContext.h" />
+ <ClInclude Include="intermediate.h" />
+ <ClInclude Include="localintermediate.h" />
+ <ClInclude Include="MapLongVariableNames.h" />
+ <ClInclude Include="MMap.h" />
+ <ClInclude Include="osinclude.h" />
+ <ClInclude Include="ParseHelper.h" />
+ <ClInclude Include="PoolAlloc.h" />
+ <ClInclude Include="QualifierAlive.h" />
+ <ClInclude Include="RemoveTree.h" />
+ <ClInclude Include="RenameFunction.h" />
+ <ClInclude Include="..\..\include\GLSLANG\ShaderLang.h" />
+ <ClInclude Include="ShHandle.h" />
+ <ClInclude Include="SymbolTable.h" />
+ <ClInclude Include="Types.h" />
+ <ClInclude Include="util.h" />
+ <ClInclude Include="ValidateLimitations.h" />
+ <ClInclude Include="VariableInfo.h" />
+ <ClInclude Include="VariablePacker.h" />
+ <ClInclude Include="glslang_tab.h" />
+ <ClInclude Include="timing\RestrictFragmentShaderTiming.h" />
+ <ClInclude Include="timing\RestrictVertexShaderTiming.h" />
+ <ClInclude Include="depgraph\DependencyGraph.h" />
+ <ClInclude Include="depgraph\DependencyGraphBuilder.h" />
+ <ClInclude Include="depgraph\DependencyGraphOutput.h" />
+ <ClInclude Include="..\third_party\compiler\ArrayBoundsClamper.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/src/compiler/translator_common.vcxproj.filters b/src/compiler/translator_common.vcxproj.filters
new file mode 100644
index 00000000..e5692b44
--- /dev/null
+++ b/src/compiler/translator_common.vcxproj.filters
@@ -0,0 +1,271 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Source Files\generated">
+ <UniqueIdentifier>{eb8da157-b29c-43c3-880d-54679e176dc5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\depgraph">
+ <UniqueIdentifier>{b5410d3a-c3c8-4ae6-843a-b000d652632e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\timing">
+ <UniqueIdentifier>{a9847611-dcd5-4c89-8262-a22b96c7c98d}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Header Files\generated">
+ <UniqueIdentifier>{094f7115-35d3-4c63-870c-ab5f393dc2c2}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\timing">
+ <UniqueIdentifier>{5f5742e9-15e1-43b4-b1e7-0c118be14e04}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\depgraph">
+ <UniqueIdentifier>{c4007e35-3c11-44d6-95f7-bb81db528068}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="BuiltInFunctionEmulator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Compiler.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="debug.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DetectCallDepth.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Diagnostics.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DirectiveHandler.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ForLoopUnroll.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="InfoSink.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Initialize.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="InitializeDll.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="InitializeParseContext.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Intermediate.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="intermOut.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IntermTraverse.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="MapLongVariableNames.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ossource_win.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="parseConst.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ParseHelper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PoolAlloc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="QualifierAlive.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="RemoveTree.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ShaderLang.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SymbolTable.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ValidateLimitations.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VariableInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VariablePacker.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="glslang_lex.cpp">
+ <Filter>Source Files\generated</Filter>
+ </ClCompile>
+ <ClCompile Include="glslang_tab.cpp">
+ <Filter>Source Files\generated</Filter>
+ </ClCompile>
+ <ClCompile Include="depgraph\DependencyGraph.cpp">
+ <Filter>Source Files\depgraph</Filter>
+ </ClCompile>
+ <ClCompile Include="depgraph\DependencyGraphBuilder.cpp">
+ <Filter>Source Files\depgraph</Filter>
+ </ClCompile>
+ <ClCompile Include="depgraph\DependencyGraphOutput.cpp">
+ <Filter>Source Files\depgraph</Filter>
+ </ClCompile>
+ <ClCompile Include="depgraph\DependencyGraphTraverse.cpp">
+ <Filter>Source Files\depgraph</Filter>
+ </ClCompile>
+ <ClCompile Include="timing\RestrictFragmentShaderTiming.cpp">
+ <Filter>Source Files\timing</Filter>
+ </ClCompile>
+ <ClCompile Include="timing\RestrictVertexShaderTiming.cpp">
+ <Filter>Source Files\timing</Filter>
+ </ClCompile>
+ <ClCompile Include="ArrayBoundsClamper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="BaseTypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BuiltInFunctionEmulator.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Common.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ConstantUnion.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="debug.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="DetectCallDepth.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Diagnostics.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="DirectiveHandler.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ForLoopUnroll.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="InfoSink.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Initialize.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="InitializeDll.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="InitializeGlobals.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="InitializeParseContext.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="intermediate.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="localintermediate.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="MapLongVariableNames.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="MMap.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="osinclude.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ParseHelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="PoolAlloc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="QualifierAlive.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="RemoveTree.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="RenameFunction.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\GLSLANG\ShaderLang.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ShHandle.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SymbolTable.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Types.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ValidateLimitations.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VariableInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VariablePacker.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="glslang_tab.h">
+ <Filter>Header Files\generated</Filter>
+ </ClInclude>
+ <ClInclude Include="timing\RestrictFragmentShaderTiming.h">
+ <Filter>Header Files\timing</Filter>
+ </ClInclude>
+ <ClInclude Include="timing\RestrictVertexShaderTiming.h">
+ <Filter>Header Files\timing</Filter>
+ </ClInclude>
+ <ClInclude Include="depgraph\DependencyGraph.h">
+ <Filter>Header Files\depgraph</Filter>
+ </ClInclude>
+ <ClInclude Include="depgraph\DependencyGraphBuilder.h">
+ <Filter>Header Files\depgraph</Filter>
+ </ClInclude>
+ <ClInclude Include="depgraph\DependencyGraphOutput.h">
+ <Filter>Header Files\depgraph</Filter>
+ </ClInclude>
+ <ClInclude Include="HashNames.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ArrayBoundsClamper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="glslang.l">
+ <Filter>Source Files</Filter>
+ </CustomBuild>
+ <CustomBuild Include="glslang.y">
+ <Filter>Source Files</Filter>
+ </CustomBuild>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/compiler/translator_hlsl.vcxproj b/src/compiler/translator_hlsl.vcxproj
new file mode 100644
index 00000000..0aade59a
--- /dev/null
+++ b/src/compiler/translator_hlsl.vcxproj
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{5620F0E4-6C43-49BC-A178-B804E1A0C3A7}</ProjectGuid>
+ <RootNamespace>CrossCompilerHLSL</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\hlsl\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\hlsl\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="CodeGenHLSL.cpp" />
+ <ClCompile Include="DetectDiscontinuity.cpp" />
+ <ClCompile Include="OutputHLSL.cpp" />
+ <ClCompile Include="SearchSymbol.cpp" />
+ <ClCompile Include="TranslatorHLSL.cpp" />
+ <ClCompile Include="UnfoldShortCircuit.cpp" />
+ <ClCompile Include="Uniform.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="DetectDiscontinuity.h" />
+ <ClInclude Include="OutputHLSL.h" />
+ <ClInclude Include="SearchSymbol.h" />
+ <ClInclude Include="TranslatorHLSL.h" />
+ <ClInclude Include="UnfoldShortCircuit.h" />
+ <ClInclude Include="Uniform.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/compiler/translator_hlsl.vcxproj.filters b/src/compiler/translator_hlsl.vcxproj.filters
new file mode 100644
index 00000000..f4824dc1
--- /dev/null
+++ b/src/compiler/translator_hlsl.vcxproj.filters
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="CodeGenHLSL.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DetectDiscontinuity.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="OutputHLSL.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SearchSymbol.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="TranslatorHLSL.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="UnfoldShortCircuit.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Uniform.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="DetectDiscontinuity.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="OutputHLSL.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SearchSymbol.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="TranslatorHLSL.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="UnfoldShortCircuit.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Uniform.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/compiler/util.cpp b/src/compiler/util.cpp
new file mode 100644
index 00000000..b46e4d0e
--- /dev/null
+++ b/src/compiler/util.cpp
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 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.
+//
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+#ifdef _MSC_VER
+ #include <locale.h>
+#else
+ #include <sstream>
+#endif
+
+double atof_dot(const char *str)
+{
+#ifdef _MSC_VER
+ _locale_t l = _create_locale(LC_NUMERIC, "C");
+ double result = _atof_l(str, l);
+ _free_locale(l);
+ return result;
+#else
+ double result;
+ std::istringstream s(str);
+ std::locale l("C");
+ s.imbue(l);
+ s >> result;
+ return result;
+#endif
+}
diff --git a/src/compiler/util.h b/src/compiler/util.h
new file mode 100644
index 00000000..35288b73
--- /dev/null
+++ b/src/compiler/util.h
@@ -0,0 +1,21 @@
+//
+// 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.
+//
+
+#ifndef COMPILER_UTIL_H
+#define COMPILER_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// atof_dot is like atof but forcing C locale, i.e. forcing '.' as decimal point.
+double atof_dot(const char *str);
+
+#ifdef __cplusplus
+} // end extern "C"
+#endif
+
+#endif // COMPILER_UTIL_H
diff --git a/src/libEGL/Config.cpp b/src/libEGL/Config.cpp
new file mode 100644
index 00000000..5488cb6f
--- /dev/null
+++ b/src/libEGL/Config.cpp
@@ -0,0 +1,340 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Config.cpp: Implements the egl::Config class, describing the format, type
+// and size for an egl::Surface. Implements EGLConfig and related functionality.
+// [EGL 1.4] section 3.4 page 15.
+
+#include "libEGL/Config.h"
+
+#include <algorithm>
+#include <vector>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "common/debug.h"
+
+using namespace std;
+
+namespace egl
+{
+Config::Config(rx::ConfigDesc desc, EGLint minInterval, EGLint maxInterval, EGLint texWidth, EGLint texHeight)
+ : mRenderTargetFormat(desc.renderTargetFormat), mDepthStencilFormat(desc.depthStencilFormat), mMultiSample(desc.multiSample)
+{
+ mBindToTextureRGB = EGL_FALSE;
+ mBindToTextureRGBA = EGL_FALSE;
+ switch (desc.renderTargetFormat)
+ {
+ case GL_RGB5_A1:
+ mBufferSize = 16;
+ mRedSize = 5;
+ mGreenSize = 5;
+ mBlueSize = 5;
+ mAlphaSize = 1;
+ break;
+ case GL_RGBA8_OES:
+ mBufferSize = 32;
+ mRedSize = 8;
+ mGreenSize = 8;
+ mBlueSize = 8;
+ mAlphaSize = 8;
+ mBindToTextureRGBA = true;
+ break;
+ case GL_RGB565:
+ mBufferSize = 16;
+ mRedSize = 5;
+ mGreenSize = 6;
+ mBlueSize = 5;
+ mAlphaSize = 0;
+ break;
+ case GL_RGB8_OES:
+ mBufferSize = 32;
+ mRedSize = 8;
+ mGreenSize = 8;
+ mBlueSize = 8;
+ mAlphaSize = 0;
+ mBindToTextureRGB = true;
+ break;
+ case GL_BGRA8_EXT:
+ mBufferSize = 32;
+ mRedSize = 8;
+ mGreenSize = 8;
+ mBlueSize = 8;
+ mAlphaSize = 8;
+ mBindToTextureRGBA = true;
+ break;
+ default:
+ UNREACHABLE(); // Other formats should not be valid
+ }
+
+ mLuminanceSize = 0;
+ mAlphaMaskSize = 0;
+ mColorBufferType = EGL_RGB_BUFFER;
+ mConfigCaveat = (desc.fastConfig) ? EGL_NONE : EGL_SLOW_CONFIG;
+ mConfigID = 0;
+ mConformant = EGL_OPENGL_ES2_BIT;
+
+ switch (desc.depthStencilFormat)
+ {
+ case GL_NONE:
+ mDepthSize = 0;
+ mStencilSize = 0;
+ break;
+ case GL_DEPTH_COMPONENT32_OES:
+ mDepthSize = 32;
+ mStencilSize = 0;
+ break;
+ case GL_DEPTH24_STENCIL8_OES:
+ mDepthSize = 24;
+ mStencilSize = 8;
+ break;
+ case GL_DEPTH_COMPONENT24_OES:
+ mDepthSize = 24;
+ mStencilSize = 0;
+ break;
+ case GL_DEPTH_COMPONENT16:
+ mDepthSize = 16;
+ mStencilSize = 0;
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ mLevel = 0;
+ mMatchNativePixmap = EGL_NONE;
+ mMaxPBufferWidth = texWidth;
+ mMaxPBufferHeight = texHeight;
+ mMaxPBufferPixels = texWidth*texHeight;
+ mMaxSwapInterval = maxInterval;
+ mMinSwapInterval = minInterval;
+ mNativeRenderable = EGL_FALSE;
+ mNativeVisualID = 0;
+ mNativeVisualType = 0;
+ mRenderableType = EGL_OPENGL_ES2_BIT;
+ mSampleBuffers = desc.multiSample ? 1 : 0;
+ mSamples = desc.multiSample;
+ mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
+ mTransparentType = EGL_NONE;
+ mTransparentRedValue = 0;
+ mTransparentGreenValue = 0;
+ mTransparentBlueValue = 0;
+}
+
+EGLConfig Config::getHandle() const
+{
+ return (EGLConfig)(size_t)mConfigID;
+}
+
+SortConfig::SortConfig(const EGLint *attribList)
+ : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false)
+{
+ scanForWantedComponents(attribList);
+}
+
+void SortConfig::scanForWantedComponents(const EGLint *attribList)
+{
+ // [EGL] section 3.4.1 page 24
+ // Sorting rule #3: by larger total number of color bits, not considering
+ // components that are 0 or don't-care.
+ for (const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2)
+ {
+ if (attr[1] != 0 && attr[1] != EGL_DONT_CARE)
+ {
+ switch (attr[0])
+ {
+ case EGL_RED_SIZE: mWantRed = true; break;
+ case EGL_GREEN_SIZE: mWantGreen = true; break;
+ case EGL_BLUE_SIZE: mWantBlue = true; break;
+ case EGL_ALPHA_SIZE: mWantAlpha = true; break;
+ case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
+ }
+ }
+ }
+}
+
+EGLint SortConfig::wantedComponentsSize(const Config &config) const
+{
+ EGLint total = 0;
+
+ if (mWantRed) total += config.mRedSize;
+ if (mWantGreen) total += config.mGreenSize;
+ if (mWantBlue) total += config.mBlueSize;
+ if (mWantAlpha) total += config.mAlphaSize;
+ if (mWantLuminance) total += config.mLuminanceSize;
+
+ return total;
+}
+
+bool SortConfig::operator()(const Config *x, const Config *y) const
+{
+ return (*this)(*x, *y);
+}
+
+bool SortConfig::operator()(const Config &x, const Config &y) const
+{
+ #define SORT(attribute) \
+ if (x.attribute != y.attribute) \
+ { \
+ return x.attribute < y.attribute; \
+ }
+
+ META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
+ SORT(mConfigCaveat);
+
+ META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
+ SORT(mColorBufferType);
+
+ // By larger total number of color bits, only considering those that are requested to be > 0.
+ EGLint xComponentsSize = wantedComponentsSize(x);
+ EGLint yComponentsSize = wantedComponentsSize(y);
+ if (xComponentsSize != yComponentsSize)
+ {
+ return xComponentsSize > yComponentsSize;
+ }
+
+ SORT(mBufferSize);
+ SORT(mSampleBuffers);
+ SORT(mSamples);
+ SORT(mDepthSize);
+ SORT(mStencilSize);
+ SORT(mAlphaMaskSize);
+ SORT(mNativeVisualType);
+ SORT(mConfigID);
+
+ #undef SORT
+
+ return false;
+}
+
+// We'd like to use SortConfig to also eliminate duplicate configs.
+// This works as long as we never have two configs with different per-RGB-component layouts,
+// but the same total.
+// 5551 and 565 are different because R+G+B is different.
+// 5551 and 555 are different because bufferSize is different.
+const EGLint ConfigSet::mSortAttribs[] =
+{
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_LUMINANCE_SIZE, 1,
+ // BUT NOT ALPHA
+ EGL_NONE
+};
+
+ConfigSet::ConfigSet()
+ : mSet(SortConfig(mSortAttribs))
+{
+}
+
+void ConfigSet::add(rx::ConfigDesc desc, EGLint minSwapInterval, EGLint maxSwapInterval, EGLint texWidth, EGLint texHeight)
+{
+ Config config(desc, minSwapInterval, maxSwapInterval, texWidth, texHeight);
+ mSet.insert(config);
+}
+
+size_t ConfigSet::size() const
+{
+ return mSet.size();
+}
+
+bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
+{
+ vector<const Config*> passed;
+ passed.reserve(mSet.size());
+
+ for (Iterator config = mSet.begin(); config != mSet.end(); config++)
+ {
+ bool match = true;
+ const EGLint *attribute = attribList;
+
+ while (attribute[0] != EGL_NONE)
+ {
+ switch (attribute[0])
+ {
+ case EGL_BUFFER_SIZE: match = config->mBufferSize >= attribute[1]; break;
+ case EGL_ALPHA_SIZE: match = config->mAlphaSize >= attribute[1]; break;
+ case EGL_BLUE_SIZE: match = config->mBlueSize >= attribute[1]; break;
+ case EGL_GREEN_SIZE: match = config->mGreenSize >= attribute[1]; break;
+ case EGL_RED_SIZE: match = config->mRedSize >= attribute[1]; break;
+ case EGL_DEPTH_SIZE: match = config->mDepthSize >= attribute[1]; break;
+ case EGL_STENCIL_SIZE: match = config->mStencilSize >= attribute[1]; break;
+ case EGL_CONFIG_CAVEAT: match = config->mConfigCaveat == (EGLenum) attribute[1]; break;
+ case EGL_CONFIG_ID: match = config->mConfigID == attribute[1]; break;
+ case EGL_LEVEL: match = config->mLevel >= attribute[1]; break;
+ case EGL_NATIVE_RENDERABLE: match = config->mNativeRenderable == (EGLBoolean) attribute[1]; break;
+ case EGL_NATIVE_VISUAL_TYPE: match = config->mNativeVisualType == attribute[1]; break;
+ case EGL_SAMPLES: match = config->mSamples >= attribute[1]; break;
+ case EGL_SAMPLE_BUFFERS: match = config->mSampleBuffers >= attribute[1]; break;
+ case EGL_SURFACE_TYPE: match = (config->mSurfaceType & attribute[1]) == attribute[1]; break;
+ case EGL_TRANSPARENT_TYPE: match = config->mTransparentType == (EGLenum) attribute[1]; break;
+ case EGL_TRANSPARENT_BLUE_VALUE: match = config->mTransparentBlueValue == attribute[1]; break;
+ case EGL_TRANSPARENT_GREEN_VALUE: match = config->mTransparentGreenValue == attribute[1]; break;
+ case EGL_TRANSPARENT_RED_VALUE: match = config->mTransparentRedValue == attribute[1]; break;
+ case EGL_BIND_TO_TEXTURE_RGB: match = config->mBindToTextureRGB == (EGLBoolean) attribute[1]; break;
+ case EGL_BIND_TO_TEXTURE_RGBA: match = config->mBindToTextureRGBA == (EGLBoolean) attribute[1]; break;
+ case EGL_MIN_SWAP_INTERVAL: match = config->mMinSwapInterval == attribute[1]; break;
+ case EGL_MAX_SWAP_INTERVAL: match = config->mMaxSwapInterval == attribute[1]; break;
+ case EGL_LUMINANCE_SIZE: match = config->mLuminanceSize >= attribute[1]; break;
+ case EGL_ALPHA_MASK_SIZE: match = config->mAlphaMaskSize >= attribute[1]; break;
+ case EGL_COLOR_BUFFER_TYPE: match = config->mColorBufferType == (EGLenum) attribute[1]; break;
+ case EGL_RENDERABLE_TYPE: match = (config->mRenderableType & attribute[1]) == attribute[1]; break;
+ case EGL_MATCH_NATIVE_PIXMAP: match = false; UNIMPLEMENTED(); break;
+ case EGL_CONFORMANT: match = (config->mConformant & attribute[1]) == attribute[1]; break;
+ case EGL_MAX_PBUFFER_WIDTH: match = config->mMaxPBufferWidth >= attribute[1]; break;
+ case EGL_MAX_PBUFFER_HEIGHT: match = config->mMaxPBufferHeight >= attribute[1]; break;
+ case EGL_MAX_PBUFFER_PIXELS: match = config->mMaxPBufferPixels >= attribute[1]; break;
+ default:
+ return false;
+ }
+
+ if (!match)
+ {
+ break;
+ }
+
+ attribute += 2;
+ }
+
+ if (match)
+ {
+ passed.push_back(&*config);
+ }
+ }
+
+ if (configs)
+ {
+ sort(passed.begin(), passed.end(), SortConfig(attribList));
+
+ EGLint index;
+ for (index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++)
+ {
+ configs[index] = passed[index]->getHandle();
+ }
+
+ *numConfig = index;
+ }
+ else
+ {
+ *numConfig = passed.size();
+ }
+
+ return true;
+}
+
+const egl::Config *ConfigSet::get(EGLConfig configHandle)
+{
+ for (Iterator config = mSet.begin(); config != mSet.end(); config++)
+ {
+ if (config->getHandle() == configHandle)
+ {
+ return &(*config);
+ }
+ }
+
+ return NULL;
+}
+}
diff --git a/src/libEGL/Config.h b/src/libEGL/Config.h
new file mode 100644
index 00000000..680337b7
--- /dev/null
+++ b/src/libEGL/Config.h
@@ -0,0 +1,115 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Config.h: Defines the egl::Config class, describing the format, type
+// and size for an egl::Surface. Implements EGLConfig and related functionality.
+// [EGL 1.4] section 3.4 page 15.
+
+#ifndef INCLUDE_CONFIG_H_
+#define INCLUDE_CONFIG_H_
+
+#define EGLAPI
+#include <EGL/egl.h>
+
+#include <set>
+
+#include "libGLESv2/renderer/Renderer.h"
+#include "common/angleutils.h"
+
+namespace egl
+{
+class Display;
+
+class Config
+{
+ public:
+ Config(rx::ConfigDesc desc, EGLint minSwapInterval, EGLint maxSwapInterval, EGLint texWidth, EGLint texHeight);
+
+ EGLConfig getHandle() const;
+
+ const GLenum mRenderTargetFormat;
+ const GLenum mDepthStencilFormat;
+ const GLint mMultiSample;
+
+ EGLint mBufferSize; // Depth of the color buffer
+ EGLint mRedSize; // Bits of Red in the color buffer
+ EGLint mGreenSize; // Bits of Green in the color buffer
+ EGLint mBlueSize; // Bits of Blue in the color buffer
+ EGLint mLuminanceSize; // Bits of Luminance in the color buffer
+ EGLint mAlphaSize; // Bits of Alpha in the color buffer
+ EGLint mAlphaMaskSize; // Bits of Alpha Mask in the mask buffer
+ EGLBoolean mBindToTextureRGB; // True if bindable to RGB textures.
+ EGLBoolean mBindToTextureRGBA; // True if bindable to RGBA textures.
+ EGLenum mColorBufferType; // Color buffer type
+ EGLenum mConfigCaveat; // Any caveats for the configuration
+ EGLint mConfigID; // Unique EGLConfig identifier
+ EGLint mConformant; // Whether contexts created with this config are conformant
+ EGLint mDepthSize; // Bits of Z in the depth buffer
+ EGLint mLevel; // Frame buffer level
+ EGLBoolean mMatchNativePixmap; // Match the native pixmap format
+ EGLint mMaxPBufferWidth; // Maximum width of pbuffer
+ EGLint mMaxPBufferHeight; // Maximum height of pbuffer
+ EGLint mMaxPBufferPixels; // Maximum size of pbuffer
+ EGLint mMaxSwapInterval; // Maximum swap interval
+ EGLint mMinSwapInterval; // Minimum swap interval
+ EGLBoolean mNativeRenderable; // EGL_TRUE if native rendering APIs can render to surface
+ EGLint mNativeVisualID; // Handle of corresponding native visual
+ EGLint mNativeVisualType; // Native visual type of the associated visual
+ EGLint mRenderableType; // Which client rendering APIs are supported.
+ EGLint mSampleBuffers; // Number of multisample buffers
+ EGLint mSamples; // Number of samples per pixel
+ EGLint mStencilSize; // Bits of Stencil in the stencil buffer
+ EGLint mSurfaceType; // Which types of EGL surfaces are supported.
+ EGLenum mTransparentType; // Type of transparency supported
+ EGLint mTransparentRedValue; // Transparent red value
+ EGLint mTransparentGreenValue; // Transparent green value
+ EGLint mTransparentBlueValue; // Transparent blue value
+};
+
+// Function object used by STL sorting routines for ordering Configs according to [EGL] section 3.4.1 page 24.
+class SortConfig
+{
+ public:
+ explicit SortConfig(const EGLint *attribList);
+
+ bool operator()(const Config *x, const Config *y) const;
+ bool operator()(const Config &x, const Config &y) const;
+
+ private:
+ void scanForWantedComponents(const EGLint *attribList);
+ EGLint wantedComponentsSize(const Config &config) const;
+
+ bool mWantRed;
+ bool mWantGreen;
+ bool mWantBlue;
+ bool mWantAlpha;
+ bool mWantLuminance;
+};
+
+class ConfigSet
+{
+ friend Display;
+
+ public:
+ ConfigSet();
+
+ void add(rx::ConfigDesc desc, EGLint minSwapInterval, EGLint maxSwapInterval, EGLint texWidth, EGLint texHeight);
+ size_t size() const;
+ bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig);
+ const egl::Config *get(EGLConfig configHandle);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConfigSet);
+
+ typedef std::set<Config, SortConfig> Set;
+ typedef Set::iterator Iterator;
+ Set mSet;
+
+ static const EGLint mSortAttribs[];
+};
+}
+
+#endif // INCLUDE_CONFIG_H_
diff --git a/src/libEGL/Display.cpp b/src/libEGL/Display.cpp
new file mode 100644
index 00000000..8f2af794
--- /dev/null
+++ b/src/libEGL/Display.cpp
@@ -0,0 +1,537 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Display.cpp: Implements the egl::Display class, representing the abstract
+// display on which graphics are drawn. Implements EGLDisplay.
+// [EGL 1.4] section 2.1.2 page 3.
+
+#include "libEGL/Display.h"
+
+#include <algorithm>
+#include <map>
+#include <vector>
+
+#include "common/debug.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/main.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/renderer/SwapChain.h"
+
+#include "libEGL/main.h"
+#include "libEGL/Surface.h"
+
+namespace egl
+{
+namespace
+{
+ typedef std::map<EGLNativeDisplayType, Display*> DisplayMap;
+ DisplayMap displays;
+}
+
+egl::Display *Display::getDisplay(EGLNativeDisplayType displayId)
+{
+ if (displays.find(displayId) != displays.end())
+ {
+ return displays[displayId];
+ }
+
+ // FIXME: Check if displayId is a valid display device context
+
+ egl::Display *display = new egl::Display(displayId, (HDC)displayId);
+
+ displays[displayId] = display;
+ return display;
+}
+
+Display::Display(EGLNativeDisplayType displayId, HDC deviceContext) : mDc(deviceContext)
+{
+ mDisplayId = displayId;
+ mRenderer = NULL;
+}
+
+Display::~Display()
+{
+ terminate();
+
+ DisplayMap::iterator thisDisplay = displays.find(mDisplayId);
+
+ if (thisDisplay != displays.end())
+ {
+ displays.erase(thisDisplay);
+ }
+}
+
+bool Display::initialize()
+{
+ if (isInitialized())
+ {
+ return true;
+ }
+
+ mRenderer = glCreateRenderer(this, mDc, mDisplayId);
+
+ if (!mRenderer)
+ {
+ terminate();
+ return error(EGL_NOT_INITIALIZED, false);
+ }
+
+ EGLint minSwapInterval = mRenderer->getMinSwapInterval();
+ EGLint maxSwapInterval = mRenderer->getMaxSwapInterval();
+ EGLint maxTextureWidth = mRenderer->getMaxTextureWidth();
+ EGLint maxTextureHeight = mRenderer->getMaxTextureHeight();
+
+ rx::ConfigDesc *descList;
+ int numConfigs = mRenderer->generateConfigs(&descList);
+ ConfigSet configSet;
+
+ for (int i = 0; i < numConfigs; ++i)
+ configSet.add(descList[i], minSwapInterval, maxSwapInterval,
+ maxTextureWidth, maxTextureHeight);
+
+ // Give the sorted configs a unique ID and store them internally
+ EGLint index = 1;
+ for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
+ {
+ Config configuration = *config;
+ configuration.mConfigID = index;
+ index++;
+
+ mConfigSet.mSet.insert(configuration);
+ }
+
+ mRenderer->deleteConfigs(descList);
+ descList = NULL;
+
+ if (!isInitialized())
+ {
+ terminate();
+ return false;
+ }
+
+ initExtensionString();
+ initVendorString();
+
+ return true;
+}
+
+void Display::terminate()
+{
+ while (!mSurfaceSet.empty())
+ {
+ destroySurface(*mSurfaceSet.begin());
+ }
+
+ while (!mContextSet.empty())
+ {
+ destroyContext(*mContextSet.begin());
+ }
+
+ glDestroyRenderer(mRenderer);
+ mRenderer = NULL;
+}
+
+bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
+{
+ return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
+}
+
+bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
+{
+ const egl::Config *configuration = mConfigSet.get(config);
+
+ switch (attribute)
+ {
+ case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
+ case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
+ case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
+ case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
+ case EGL_RED_SIZE: *value = configuration->mRedSize; break;
+ case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
+ case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
+ case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
+ case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
+ case EGL_LEVEL: *value = configuration->mLevel; break;
+ case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
+ case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
+ case EGL_SAMPLES: *value = configuration->mSamples; break;
+ case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
+ case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
+ case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
+ case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
+ case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
+ case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
+ case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
+ case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
+ case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
+ case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
+ case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
+ case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
+ case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
+ case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
+ case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break;
+ case EGL_CONFORMANT: *value = configuration->mConformant; break;
+ case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
+ case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
+ case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+
+
+EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList)
+{
+ const Config *configuration = mConfigSet.get(config);
+ EGLint postSubBufferSupported = EGL_FALSE;
+
+ if (attribList)
+ {
+ while (*attribList != EGL_NONE)
+ {
+ switch (attribList[0])
+ {
+ case EGL_RENDER_BUFFER:
+ switch (attribList[1])
+ {
+ case EGL_BACK_BUFFER:
+ break;
+ case EGL_SINGLE_BUFFER:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ break;
+ case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
+ postSubBufferSupported = attribList[1];
+ break;
+ case EGL_VG_COLORSPACE:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ case EGL_VG_ALPHA_FORMAT:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
+ attribList += 2;
+ }
+ }
+
+ if (hasExistingWindowSurface(window))
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+
+ if (mRenderer->testDeviceLost(false))
+ {
+ if (!restoreLostDevice())
+ return EGL_NO_SURFACE;
+ }
+
+ Surface *surface = new Surface(this, configuration, window, postSubBufferSupported);
+
+ if (!surface->initialize())
+ {
+ delete surface;
+ return EGL_NO_SURFACE;
+ }
+
+ mSurfaceSet.insert(surface);
+
+ return success(surface);
+}
+
+EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
+{
+ EGLint width = 0, height = 0;
+ EGLenum textureFormat = EGL_NO_TEXTURE;
+ EGLenum textureTarget = EGL_NO_TEXTURE;
+ const Config *configuration = mConfigSet.get(config);
+
+ if (attribList)
+ {
+ while (*attribList != EGL_NONE)
+ {
+ switch (attribList[0])
+ {
+ case EGL_WIDTH:
+ width = attribList[1];
+ break;
+ case EGL_HEIGHT:
+ height = attribList[1];
+ break;
+ case EGL_LARGEST_PBUFFER:
+ if (attribList[1] != EGL_FALSE)
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_TEXTURE_FORMAT:
+ switch (attribList[1])
+ {
+ case EGL_NO_TEXTURE:
+ case EGL_TEXTURE_RGB:
+ case EGL_TEXTURE_RGBA:
+ textureFormat = attribList[1];
+ break;
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ break;
+ case EGL_TEXTURE_TARGET:
+ switch (attribList[1])
+ {
+ case EGL_NO_TEXTURE:
+ case EGL_TEXTURE_2D:
+ textureTarget = attribList[1];
+ break;
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ break;
+ case EGL_MIPMAP_TEXTURE:
+ if (attribList[1] != EGL_FALSE)
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ break;
+ case EGL_VG_COLORSPACE:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ case EGL_VG_ALPHA_FORMAT:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
+ attribList += 2;
+ }
+ }
+
+ if (width < 0 || height < 0)
+ {
+ return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+
+ if (width == 0 || height == 0)
+ {
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
+ if (textureFormat != EGL_NO_TEXTURE && !mRenderer->getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
+ {
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
+ (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
+ {
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
+ {
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
+ (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
+ {
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
+ if (mRenderer->testDeviceLost(false))
+ {
+ if (!restoreLostDevice())
+ return EGL_NO_SURFACE;
+ }
+
+ Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
+
+ if (!surface->initialize())
+ {
+ delete surface;
+ return EGL_NO_SURFACE;
+ }
+
+ mSurfaceSet.insert(surface);
+
+ return success(surface);
+}
+
+EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess)
+{
+ if (!mRenderer)
+ {
+ return NULL;
+ }
+ else if (mRenderer->testDeviceLost(false)) // Lost device
+ {
+ if (!restoreLostDevice())
+ return NULL;
+ }
+
+ gl::Context *context = glCreateContext(shareContext, mRenderer, notifyResets, robustAccess);
+ mContextSet.insert(context);
+
+ return context;
+}
+
+bool Display::restoreLostDevice()
+{
+ for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++)
+ {
+ if ((*ctx)->isResetNotificationEnabled())
+ return false; // If reset notifications have been requested, application must delete all contexts first
+ }
+
+ // Release surface resources to make the Reset() succeed
+ for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+ {
+ (*surface)->release();
+ }
+
+ if (!mRenderer->resetDevice())
+ {
+ return error(EGL_BAD_ALLOC, false);
+ }
+
+ // Restore any surfaces that may have been lost
+ for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+ {
+ (*surface)->resetSwapChain();
+ }
+
+ return true;
+}
+
+
+void Display::destroySurface(egl::Surface *surface)
+{
+ delete surface;
+ mSurfaceSet.erase(surface);
+}
+
+void Display::destroyContext(gl::Context *context)
+{
+ glDestroyContext(context);
+ mContextSet.erase(context);
+}
+
+void Display::notifyDeviceLost()
+{
+ for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++)
+ {
+ (*context)->markContextLost();
+ }
+ egl::error(EGL_CONTEXT_LOST);
+}
+
+void Display::recreateSwapChains()
+{
+ for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+ {
+ (*surface)->getSwapChain()->recreate();
+ }
+}
+
+bool Display::isInitialized() const
+{
+ return mRenderer != NULL && mConfigSet.size() > 0;
+}
+
+bool Display::isValidConfig(EGLConfig config)
+{
+ return mConfigSet.get(config) != NULL;
+}
+
+bool Display::isValidContext(gl::Context *context)
+{
+ return mContextSet.find(context) != mContextSet.end();
+}
+
+bool Display::isValidSurface(egl::Surface *surface)
+{
+ return mSurfaceSet.find(surface) != mSurfaceSet.end();
+}
+
+bool Display::hasExistingWindowSurface(HWND window)
+{
+ for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+ {
+ if ((*surface)->getWindowHandle() == window)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Display::initExtensionString()
+{
+ HMODULE swiftShader = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
+ bool shareHandleSupported = mRenderer->getShareHandleSupport();
+
+ mExtensionString = "";
+
+ // Multi-vendor (EXT) extensions
+ mExtensionString += "EGL_EXT_create_context_robustness ";
+
+ // ANGLE-specific extensions
+ if (shareHandleSupported)
+ {
+ mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
+ }
+
+ mExtensionString += "EGL_ANGLE_query_surface_pointer ";
+
+ if (swiftShader)
+ {
+ mExtensionString += "EGL_ANGLE_software_display ";
+ }
+
+ if (shareHandleSupported)
+ {
+ mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
+ }
+
+ if (mRenderer->getPostSubBufferSupport())
+ {
+ mExtensionString += "EGL_NV_post_sub_buffer";
+ }
+
+ std::string::size_type end = mExtensionString.find_last_not_of(' ');
+ if (end != std::string::npos)
+ {
+ mExtensionString.resize(end+1);
+ }
+}
+
+const char *Display::getExtensionString() const
+{
+ return mExtensionString.c_str();
+}
+
+void Display::initVendorString()
+{
+ mVendorString = "Google Inc.";
+
+ LUID adapterLuid = {0};
+
+ if (mRenderer && mRenderer->getLUID(&adapterLuid))
+ {
+ char adapterLuidString[64];
+ sprintf_s(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart);
+
+ mVendorString += adapterLuidString;
+ }
+}
+
+const char *Display::getVendorString() const
+{
+ return mVendorString.c_str();
+}
+
+}
diff --git a/src/libEGL/Display.h b/src/libEGL/Display.h
new file mode 100644
index 00000000..58c39403
--- /dev/null
+++ b/src/libEGL/Display.h
@@ -0,0 +1,94 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Display.h: Defines the egl::Display class, representing the abstract
+// display on which graphics are drawn. Implements EGLDisplay.
+// [EGL 1.4] section 2.1.2 page 3.
+
+#ifndef LIBEGL_DISPLAY_H_
+#define LIBEGL_DISPLAY_H_
+
+#include "common/system.h"
+
+#include <set>
+#include <vector>
+
+#include "libEGL/Config.h"
+
+namespace gl
+{
+class Context;
+}
+
+namespace egl
+{
+class Surface;
+
+class Display
+{
+ public:
+ ~Display();
+
+ bool initialize();
+ void terminate();
+
+ static egl::Display *getDisplay(EGLNativeDisplayType displayId);
+
+ bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig);
+ bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value);
+
+ EGLSurface createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList);
+ EGLSurface createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList);
+ EGLContext createContext(EGLConfig configHandle, const gl::Context *shareContext, bool notifyResets, bool robustAccess);
+
+ void destroySurface(egl::Surface *surface);
+ void destroyContext(gl::Context *context);
+
+ bool isInitialized() const;
+ bool isValidConfig(EGLConfig config);
+ bool isValidContext(gl::Context *context);
+ bool isValidSurface(egl::Surface *surface);
+ bool hasExistingWindowSurface(HWND window);
+
+ rx::Renderer *getRenderer() { return mRenderer; };
+
+ // exported methods must be virtual
+ virtual void notifyDeviceLost();
+ virtual void recreateSwapChains();
+
+ const char *getExtensionString() const;
+ const char *getVendorString() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Display);
+
+ Display(EGLNativeDisplayType displayId, HDC deviceContext);
+
+ bool restoreLostDevice();
+
+ EGLNativeDisplayType mDisplayId;
+ const HDC mDc;
+
+ bool mSoftwareDevice;
+
+ typedef std::set<Surface*> SurfaceSet;
+ SurfaceSet mSurfaceSet;
+
+ ConfigSet mConfigSet;
+
+ typedef std::set<gl::Context*> ContextSet;
+ ContextSet mContextSet;
+
+ rx::Renderer *mRenderer;
+
+ void initExtensionString();
+ void initVendorString();
+ std::string mExtensionString;
+ std::string mVendorString;
+};
+}
+
+#endif // LIBEGL_DISPLAY_H_
diff --git a/src/libEGL/Surface.cpp b/src/libEGL/Surface.cpp
new file mode 100644
index 00000000..539c4c62
--- /dev/null
+++ b/src/libEGL/Surface.cpp
@@ -0,0 +1,408 @@
+//
+// 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.
+//
+
+// Surface.cpp: Implements the egl::Surface class, representing a drawing surface
+// such as the client area of a window, including any back buffers.
+// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3.
+
+#include <tchar.h>
+
+#include "libEGL/Surface.h"
+
+#include "common/debug.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/renderer/SwapChain.h"
+#include "libGLESv2/main.h"
+
+#include "libEGL/main.h"
+#include "libEGL/Display.h"
+
+namespace egl
+{
+
+Surface::Surface(Display *display, const Config *config, HWND window, EGLint postSubBufferSupported)
+ : mDisplay(display), mConfig(config), mWindow(window), mPostSubBufferSupported(postSubBufferSupported)
+{
+ mRenderer = mDisplay->getRenderer();
+ mSwapChain = NULL;
+ mShareHandle = NULL;
+ mTexture = NULL;
+ mTextureFormat = EGL_NO_TEXTURE;
+ mTextureTarget = EGL_NO_TEXTURE;
+
+ mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
+ mRenderBuffer = EGL_BACK_BUFFER;
+ mSwapBehavior = EGL_BUFFER_PRESERVED;
+ mSwapInterval = -1;
+ mWidth = -1;
+ mHeight = -1;
+ setSwapInterval(1);
+
+ subclassWindow();
+}
+
+Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType)
+ : mDisplay(display), mWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE)
+{
+ mRenderer = mDisplay->getRenderer();
+ mSwapChain = NULL;
+ mWindowSubclassed = false;
+ mTexture = NULL;
+ mTextureFormat = textureFormat;
+ mTextureTarget = textureType;
+
+ mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
+ mRenderBuffer = EGL_BACK_BUFFER;
+ mSwapBehavior = EGL_BUFFER_PRESERVED;
+ mSwapInterval = -1;
+ setSwapInterval(1);
+}
+
+Surface::~Surface()
+{
+ unsubclassWindow();
+ release();
+}
+
+bool Surface::initialize()
+{
+ if (!resetSwapChain())
+ return false;
+
+ return true;
+}
+
+void Surface::release()
+{
+ delete mSwapChain;
+ mSwapChain = NULL;
+
+ if (mTexture)
+ {
+ mTexture->releaseTexImage();
+ mTexture = NULL;
+ }
+}
+
+bool Surface::resetSwapChain()
+{
+ ASSERT(!mSwapChain);
+
+ int width;
+ int height;
+
+ if (mWindow)
+ {
+ RECT windowRect;
+ if (!GetClientRect(getWindowHandle(), &windowRect))
+ {
+ ASSERT(false);
+
+ ERR("Could not retrieve the window dimensions");
+ return error(EGL_BAD_SURFACE, false);
+ }
+
+ width = windowRect.right - windowRect.left;
+ height = windowRect.bottom - windowRect.top;
+ }
+ else
+ {
+ // non-window surface - size is determined at creation
+ width = mWidth;
+ height = mHeight;
+ }
+
+ mSwapChain = mRenderer->createSwapChain(mWindow, mShareHandle,
+ mConfig->mRenderTargetFormat,
+ mConfig->mDepthStencilFormat);
+ if (!mSwapChain)
+ {
+ return error(EGL_BAD_ALLOC, false);
+ }
+
+ if (!resetSwapChain(width, height))
+ {
+ delete mSwapChain;
+ mSwapChain = NULL;
+ return false;
+ }
+
+ return true;
+}
+
+bool Surface::resizeSwapChain(int backbufferWidth, int backbufferHeight)
+{
+ ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
+ ASSERT(mSwapChain);
+
+ EGLint status = mSwapChain->resize(backbufferWidth, backbufferHeight);
+
+ if (status == EGL_CONTEXT_LOST)
+ {
+ mDisplay->notifyDeviceLost();
+ return false;
+ }
+ else if (status != EGL_SUCCESS)
+ {
+ return error(status, false);
+ }
+
+ mWidth = backbufferWidth;
+ mHeight = backbufferHeight;
+
+ return true;
+}
+
+bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight)
+{
+ ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0);
+ ASSERT(mSwapChain);
+
+ EGLint status = mSwapChain->reset(backbufferWidth, backbufferHeight, mSwapInterval);
+
+ if (status == EGL_CONTEXT_LOST)
+ {
+ mRenderer->notifyDeviceLost();
+ return false;
+ }
+ else if (status != EGL_SUCCESS)
+ {
+ return error(status, false);
+ }
+
+ mWidth = backbufferWidth;
+ mHeight = backbufferHeight;
+ mSwapIntervalDirty = false;
+
+ return true;
+}
+
+bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ if (!mSwapChain)
+ {
+ return true;
+ }
+
+ if (x + width > mWidth)
+ {
+ width = mWidth - x;
+ }
+
+ if (y + height > mHeight)
+ {
+ height = mHeight - y;
+ }
+
+ if (width == 0 || height == 0)
+ {
+ return true;
+ }
+
+ EGLint status = mSwapChain->swapRect(x, y, width, height);
+
+ if (status == EGL_CONTEXT_LOST)
+ {
+ mRenderer->notifyDeviceLost();
+ return false;
+ }
+ else if (status != EGL_SUCCESS)
+ {
+ return error(status, false);
+ }
+
+ checkForOutOfDateSwapChain();
+
+ return true;
+}
+
+HWND Surface::getWindowHandle()
+{
+ return mWindow;
+}
+
+
+#define kSurfaceProperty _TEXT("Egl::SurfaceOwner")
+#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc")
+
+static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+ if (message == WM_SIZE)
+ {
+ Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty));
+ if(surf)
+ {
+ surf->checkForOutOfDateSwapChain();
+ }
+ }
+ WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc));
+ return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam);
+}
+
+void Surface::subclassWindow()
+{
+ if (!mWindow)
+ {
+ return;
+ }
+
+ DWORD processId;
+ DWORD threadId = GetWindowThreadProcessId(mWindow, &processId);
+ if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId())
+ {
+ return;
+ }
+
+ SetLastError(0);
+ LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
+ if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS)
+ {
+ mWindowSubclassed = false;
+ return;
+ }
+
+ SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this));
+ SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc));
+ mWindowSubclassed = true;
+}
+
+void Surface::unsubclassWindow()
+{
+ if(!mWindowSubclassed)
+ {
+ return;
+ }
+
+ // un-subclass
+ LONG_PTR parentWndFunc = reinterpret_cast<LONG_PTR>(GetProp(mWindow, kParentWndProc));
+
+ // Check the windowproc is still SurfaceWindowProc.
+ // If this assert fails, then it is likely the application has subclassed the
+ // hwnd as well and did not unsubclass before destroying its EGL context. The
+ // application should be modified to either subclass before initializing the
+ // EGL context, or to unsubclass before destroying the EGL context.
+ if(parentWndFunc)
+ {
+ LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc);
+ ASSERT(prevWndFunc == reinterpret_cast<LONG_PTR>(SurfaceWindowProc));
+ }
+
+ RemoveProp(mWindow, kSurfaceProperty);
+ RemoveProp(mWindow, kParentWndProc);
+ mWindowSubclassed = false;
+}
+
+bool Surface::checkForOutOfDateSwapChain()
+{
+ RECT client;
+ if (!GetClientRect(getWindowHandle(), &client))
+ {
+ ASSERT(false);
+ return false;
+ }
+
+ // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information.
+ int clientWidth = client.right - client.left;
+ int clientHeight = client.bottom - client.top;
+ bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight();
+
+ if (mSwapIntervalDirty)
+ {
+ resetSwapChain(clientWidth, clientHeight);
+ }
+ else if (sizeDirty)
+ {
+ resizeSwapChain(clientWidth, clientHeight);
+ }
+
+ if (mSwapIntervalDirty || sizeDirty)
+ {
+ if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this)
+ {
+ glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Surface::swap()
+{
+ return swapRect(0, 0, mWidth, mHeight);
+}
+
+bool Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ if (!mPostSubBufferSupported)
+ {
+ // Spec is not clear about how this should be handled.
+ return true;
+ }
+
+ return swapRect(x, y, width, height);
+}
+
+EGLint Surface::getWidth() const
+{
+ return mWidth;
+}
+
+EGLint Surface::getHeight() const
+{
+ return mHeight;
+}
+
+EGLint Surface::isPostSubBufferSupported() const
+{
+ return mPostSubBufferSupported;
+}
+
+rx::SwapChain *Surface::getSwapChain() const
+{
+ return mSwapChain;
+}
+
+void Surface::setSwapInterval(EGLint interval)
+{
+ if (mSwapInterval == interval)
+ {
+ return;
+ }
+
+ mSwapInterval = interval;
+ mSwapInterval = std::max(mSwapInterval, mRenderer->getMinSwapInterval());
+ mSwapInterval = std::min(mSwapInterval, mRenderer->getMaxSwapInterval());
+
+ mSwapIntervalDirty = true;
+}
+
+EGLenum Surface::getTextureFormat() const
+{
+ return mTextureFormat;
+}
+
+EGLenum Surface::getTextureTarget() const
+{
+ return mTextureTarget;
+}
+
+void Surface::setBoundTexture(gl::Texture2D *texture)
+{
+ mTexture = texture;
+}
+
+gl::Texture2D *Surface::getBoundTexture() const
+{
+ return mTexture;
+}
+
+EGLenum Surface::getFormat() const
+{
+ return mConfig->mRenderTargetFormat;
+}
+}
diff --git a/src/libEGL/Surface.h b/src/libEGL/Surface.h
new file mode 100644
index 00000000..938b800c
--- /dev/null
+++ b/src/libEGL/Surface.h
@@ -0,0 +1,108 @@
+//
+// 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.
+//
+
+// Surface.h: Defines the egl::Surface class, representing a drawing surface
+// such as the client area of a window, including any back buffers.
+// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3.
+
+#ifndef LIBEGL_SURFACE_H_
+#define LIBEGL_SURFACE_H_
+
+#define EGLAPI
+#include <EGL/egl.h>
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+class Texture2D;
+}
+namespace rx
+{
+class Renderer;
+class SwapChain;
+}
+
+namespace egl
+{
+class Display;
+class Config;
+
+class Surface
+{
+ public:
+ Surface(Display *display, const egl::Config *config, HWND window, EGLint postSubBufferSupported);
+ Surface(Display *display, const egl::Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureTarget);
+
+ ~Surface();
+
+ bool initialize();
+ void release();
+ bool resetSwapChain();
+
+ HWND getWindowHandle();
+ bool swap();
+ bool postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height);
+
+ virtual EGLint getWidth() const;
+ virtual EGLint getHeight() const;
+
+ virtual EGLint isPostSubBufferSupported() const;
+
+ virtual rx::SwapChain *getSwapChain() const;
+
+ void setSwapInterval(EGLint interval);
+ bool checkForOutOfDateSwapChain(); // Returns true if swapchain changed due to resize or interval update
+
+ virtual EGLenum getTextureFormat() const;
+ virtual EGLenum getTextureTarget() const;
+ virtual EGLenum getFormat() const;
+
+ virtual void setBoundTexture(gl::Texture2D *texture);
+ virtual gl::Texture2D *getBoundTexture() const;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(Surface);
+
+ Display *const mDisplay;
+ rx::Renderer *mRenderer;
+
+ HANDLE mShareHandle;
+ rx::SwapChain *mSwapChain;
+
+ void subclassWindow();
+ void unsubclassWindow();
+ bool resizeSwapChain(int backbufferWidth, int backbufferHeight);
+ bool resetSwapChain(int backbufferWidth, int backbufferHeight);
+ bool swapRect(EGLint x, EGLint y, EGLint width, EGLint height);
+
+ const HWND mWindow; // Window that the surface is created for.
+ bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking
+ const egl::Config *mConfig; // EGL config surface was created with
+ EGLint mHeight; // Height of surface
+ EGLint mWidth; // Width of surface
+// EGLint horizontalResolution; // Horizontal dot pitch
+// EGLint verticalResolution; // Vertical dot pitch
+// EGLBoolean largestPBuffer; // If true, create largest pbuffer possible
+// EGLBoolean mipmapTexture; // True if texture has mipmaps
+// EGLint mipmapLevel; // Mipmap level to render to
+// EGLenum multisampleResolve; // Multisample resolve behavior
+ EGLint mPixelAspectRatio; // Display aspect ratio
+ EGLenum mRenderBuffer; // Render buffer
+ EGLenum mSwapBehavior; // Buffer swap behavior
+ EGLenum mTextureFormat; // Format of texture: RGB, RGBA, or no texture
+ EGLenum mTextureTarget; // Type of texture: 2D or no texture
+// EGLenum vgAlphaFormat; // Alpha format for OpenVG
+// EGLenum vgColorSpace; // Color space for OpenVG
+ EGLint mSwapInterval;
+ EGLint mPostSubBufferSupported;
+
+ bool mSwapIntervalDirty;
+ gl::Texture2D *mTexture;
+};
+}
+
+#endif // LIBEGL_SURFACE_H_
diff --git a/src/libEGL/libEGL.cpp b/src/libEGL/libEGL.cpp
new file mode 100644
index 00000000..6e10c392
--- /dev/null
+++ b/src/libEGL/libEGL.cpp
@@ -0,0 +1,1188 @@
+//
+// 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.
+//
+
+// libEGL.cpp: Implements the exported EGL functions.
+
+#include <exception>
+
+#include "common/debug.h"
+#include "common/version.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/main.h"
+#include "libGLESv2/renderer/SwapChain.h"
+
+#include "libEGL/main.h"
+#include "libEGL/Display.h"
+#include "libEGL/Surface.h"
+
+bool validateDisplay(egl::Display *display)
+{
+ if (display == EGL_NO_DISPLAY)
+ {
+ return egl::error(EGL_BAD_DISPLAY, false);
+ }
+
+ if (!display->isInitialized())
+ {
+ return egl::error(EGL_NOT_INITIALIZED, false);
+ }
+
+ return true;
+}
+
+bool validateConfig(egl::Display *display, EGLConfig config)
+{
+ if (!validateDisplay(display))
+ {
+ return false;
+ }
+
+ if (!display->isValidConfig(config))
+ {
+ return egl::error(EGL_BAD_CONFIG, false);
+ }
+
+ return true;
+}
+
+bool validateContext(egl::Display *display, gl::Context *context)
+{
+ if (!validateDisplay(display))
+ {
+ return false;
+ }
+
+ if (!display->isValidContext(context))
+ {
+ return egl::error(EGL_BAD_CONTEXT, false);
+ }
+
+ return true;
+}
+
+bool validateSurface(egl::Display *display, egl::Surface *surface)
+{
+ if (!validateDisplay(display))
+ {
+ return false;
+ }
+
+ if (!display->isValidSurface(surface))
+ {
+ return egl::error(EGL_BAD_SURFACE, false);
+ }
+
+ return true;
+}
+
+extern "C"
+{
+EGLint __stdcall eglGetError(void)
+{
+ EVENT("()");
+
+ EGLint error = egl::getCurrentError();
+
+ if (error != EGL_SUCCESS)
+ {
+ egl::setCurrentError(EGL_SUCCESS);
+ }
+
+ return error;
+}
+
+EGLDisplay __stdcall eglGetDisplay(EGLNativeDisplayType display_id)
+{
+ EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id);
+
+ try
+ {
+ return egl::Display::getDisplay(display_id);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_NO_DISPLAY);
+ }
+}
+
+EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)",
+ dpy, major, minor);
+
+ try
+ {
+ if (dpy == EGL_NO_DISPLAY)
+ {
+ return egl::error(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!display->initialize())
+ {
+ return egl::error(EGL_NOT_INITIALIZED, EGL_FALSE);
+ }
+
+ if (major) *major = 1;
+ if (minor) *minor = 4;
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglTerminate(EGLDisplay dpy)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy);
+
+ try
+ {
+ if (dpy == EGL_NO_DISPLAY)
+ {
+ return egl::error(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ display->terminate();
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateDisplay(display))
+ {
+ return NULL;
+ }
+
+ switch (name)
+ {
+ case EGL_CLIENT_APIS:
+ return egl::success("OpenGL_ES");
+ case EGL_EXTENSIONS:
+ return egl::success(display->getExtensionString());
+ case EGL_VENDOR:
+ return egl::success(display->getVendorString());
+ case EGL_VERSION:
+ return egl::success("1.4 (ANGLE " VERSION_STRING ")");
+ }
+
+ return egl::error(EGL_BAD_PARAMETER, (const char*)NULL);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, (const char*)NULL);
+ }
+}
+
+EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, "
+ "EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
+ dpy, configs, config_size, num_config);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateDisplay(display))
+ {
+ return EGL_FALSE;
+ }
+
+ if (!num_config)
+ {
+ return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ const EGLint attribList[] = {EGL_NONE};
+
+ if (!display->getConfigs(configs, attribList, config_size, num_config))
+ {
+ return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, "
+ "EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
+ dpy, attrib_list, configs, config_size, num_config);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateDisplay(display))
+ {
+ return EGL_FALSE;
+ }
+
+ if (!num_config)
+ {
+ return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ const EGLint attribList[] = {EGL_NONE};
+
+ if (!attrib_list)
+ {
+ attrib_list = attribList;
+ }
+
+ display->getConfigs(configs, attrib_list, config_size, num_config);
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
+ dpy, config, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_FALSE;
+ }
+
+ if (!display->getConfigAttrib(config, attribute, value))
+ {
+ return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, "
+ "const EGLint *attrib_list = 0x%0.8p)", dpy, config, win, attrib_list);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_SURFACE;
+ }
+
+ HWND window = (HWND)win;
+
+ if (!IsWindow(window))
+ {
+ return egl::error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
+ return display->createWindowSurface(window, config, attrib_list);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+}
+
+EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)",
+ dpy, config, attrib_list);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_SURFACE;
+ }
+
+ return display->createOffscreenSurface(config, NULL, attrib_list);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+}
+
+EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = 0x%0.8p, "
+ "const EGLint *attrib_list = 0x%0.8p)", dpy, config, pixmap, attrib_list);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_SURFACE;
+ }
+
+ UNIMPLEMENTED(); // FIXME
+
+ return egl::success(EGL_NO_SURFACE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+}
+
+EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (surface == EGL_NO_SURFACE)
+ {
+ return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ display->destroySurface((egl::Surface*)surface);
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
+ dpy, surface, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = (egl::Surface*)surface;
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (surface == EGL_NO_SURFACE)
+ {
+ return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ switch (attribute)
+ {
+ case EGL_VG_ALPHA_FORMAT:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_VG_COLORSPACE:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_CONFIG_ID:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_HEIGHT:
+ *value = eglSurface->getHeight();
+ break;
+ case EGL_HORIZONTAL_RESOLUTION:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_LARGEST_PBUFFER:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_MIPMAP_TEXTURE:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_MIPMAP_LEVEL:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_MULTISAMPLE_RESOLVE:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_PIXEL_ASPECT_RATIO:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_RENDER_BUFFER:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_SWAP_BEHAVIOR:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_TEXTURE_FORMAT:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_TEXTURE_TARGET:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_VERTICAL_RESOLUTION:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_WIDTH:
+ *value = eglSurface->getWidth();
+ break;
+ case EGL_POST_SUB_BUFFER_SUPPORTED_NV:
+ *value = eglSurface->isPostSubBufferSupported();
+ break;
+ default:
+ return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value)
+{
+ TRACE("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, void **value = 0x%0.8p)",
+ dpy, surface, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = (egl::Surface*)surface;
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (surface == EGL_NO_SURFACE)
+ {
+ return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ switch (attribute)
+ {
+ case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
+ {
+ rx::SwapChain *swapchain = eglSurface->getSwapChain();
+ *value = (void*) (swapchain ? swapchain->getShareHandle() : NULL);
+ }
+ break;
+ default:
+ return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglBindAPI(EGLenum api)
+{
+ EVENT("(EGLenum api = 0x%X)", api);
+
+ try
+ {
+ switch (api)
+ {
+ case EGL_OPENGL_API:
+ case EGL_OPENVG_API:
+ return egl::error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation
+ case EGL_OPENGL_ES_API:
+ break;
+ default:
+ return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ egl::setCurrentAPI(api);
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLenum __stdcall eglQueryAPI(void)
+{
+ EVENT("()");
+
+ try
+ {
+ EGLenum API = egl::getCurrentAPI();
+
+ return egl::success(API);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglWaitClient(void)
+{
+ EVENT("()");
+
+ try
+ {
+ UNIMPLEMENTED(); // FIXME
+
+ return egl::success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglReleaseThread(void)
+{
+ EVENT("()");
+
+ try
+ {
+ eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, "
+ "EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)",
+ dpy, buftype, buffer, config, attrib_list);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_SURFACE;
+ }
+
+ if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || !buffer)
+ {
+ return egl::error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+
+ return display->createOffscreenSurface(config, (HANDLE)buffer, attrib_list);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+}
+
+EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint value = %d)",
+ dpy, surface, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ UNIMPLEMENTED(); // FIXME
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (buffer != EGL_BACK_BUFFER)
+ {
+ return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
+ {
+ return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ if (eglSurface->getBoundTexture())
+ {
+ return egl::error(EGL_BAD_ACCESS, EGL_FALSE);
+ }
+
+ if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
+ {
+ return egl::error(EGL_BAD_MATCH, EGL_FALSE);
+ }
+
+ if (!glBindTexImage(eglSurface))
+ {
+ return egl::error(EGL_BAD_MATCH, EGL_FALSE);
+ }
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (buffer != EGL_BACK_BUFFER)
+ {
+ return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
+ {
+ return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
+ {
+ return egl::error(EGL_BAD_MATCH, EGL_FALSE);
+ }
+
+ gl::Texture2D *texture = eglSurface->getBoundTexture();
+
+ if (texture)
+ {
+ texture->releaseTexImage();
+ }
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateDisplay(display))
+ {
+ return EGL_FALSE;
+ }
+
+ egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
+
+ if (draw_surface == NULL)
+ {
+ return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ draw_surface->setSwapInterval(interval);
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = 0x%0.8p, "
+ "const EGLint *attrib_list = 0x%0.8p)", dpy, config, share_context, attrib_list);
+
+ try
+ {
+ // Get the requested client version (default is 1) and check it is two.
+ EGLint client_version = 1;
+ bool reset_notification = false;
+ bool robust_access = false;
+
+ if (attrib_list)
+ {
+ for (const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
+ {
+ switch (attribute[0])
+ {
+ case EGL_CONTEXT_CLIENT_VERSION:
+ client_version = attribute[1];
+ break;
+ case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT:
+ if (attribute[1] == EGL_TRUE)
+ {
+ return egl::error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); // Unimplemented
+ // robust_access = true;
+ }
+ else if (attribute[1] != EGL_FALSE)
+ return egl::error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
+ break;
+ case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT:
+ if (attribute[1] == EGL_LOSE_CONTEXT_ON_RESET_EXT)
+ reset_notification = true;
+ else if (attribute[1] != EGL_NO_RESET_NOTIFICATION_EXT)
+ return egl::error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
+ break;
+ default:
+ return egl::error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
+ }
+ }
+ }
+
+ if (client_version != 2)
+ {
+ return egl::error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
+ }
+
+ if (share_context && static_cast<gl::Context*>(share_context)->isResetNotificationEnabled() != reset_notification)
+ {
+ return egl::error(EGL_BAD_MATCH, EGL_NO_CONTEXT);
+ }
+
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_CONTEXT;
+ }
+
+ EGLContext context = display->createContext(config, static_cast<gl::Context*>(share_context), reset_notification, robust_access);
+
+ if (context)
+ return egl::success(context);
+ else
+ return egl::error(EGL_CONTEXT_LOST, EGL_NO_CONTEXT);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+ }
+}
+
+EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ gl::Context *context = static_cast<gl::Context*>(ctx);
+
+ if (!validateContext(display, context))
+ {
+ return EGL_FALSE;
+ }
+
+ if (ctx == EGL_NO_CONTEXT)
+ {
+ return egl::error(EGL_BAD_CONTEXT, EGL_FALSE);
+ }
+
+ display->destroyContext(context);
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)",
+ dpy, draw, read, ctx);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ gl::Context *context = static_cast<gl::Context*>(ctx);
+
+ if (ctx != EGL_NO_CONTEXT && !validateContext(display, context))
+ {
+ return EGL_FALSE;
+ }
+
+ if (dpy != EGL_NO_DISPLAY)
+ {
+ rx::Renderer *renderer = display->getRenderer();
+ if (renderer->testDeviceLost(true))
+ {
+ return EGL_FALSE;
+ }
+
+ if (renderer->isDeviceLost())
+ {
+ return egl::error(EGL_CONTEXT_LOST, EGL_FALSE);
+ }
+ }
+
+ if ((draw != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(draw))) ||
+ (read != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(read))))
+ {
+ return EGL_FALSE;
+ }
+
+ if (draw != read)
+ {
+ UNIMPLEMENTED(); // FIXME
+ }
+
+ egl::setCurrentDisplay(dpy);
+ egl::setCurrentDrawSurface(draw);
+ egl::setCurrentReadSurface(read);
+
+ glMakeCurrent(context, display, static_cast<egl::Surface*>(draw));
+
+ return egl::success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLContext __stdcall eglGetCurrentContext(void)
+{
+ EVENT("()");
+
+ try
+ {
+ EGLContext context = glGetCurrentContext();
+
+ return egl::success(context);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+ }
+}
+
+EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw)
+{
+ EVENT("(EGLint readdraw = %d)", readdraw);
+
+ try
+ {
+ if (readdraw == EGL_READ)
+ {
+ EGLSurface read = egl::getCurrentReadSurface();
+ return egl::success(read);
+ }
+ else if (readdraw == EGL_DRAW)
+ {
+ EGLSurface draw = egl::getCurrentDrawSurface();
+ return egl::success(draw);
+ }
+ else
+ {
+ return egl::error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+}
+
+EGLDisplay __stdcall eglGetCurrentDisplay(void)
+{
+ EVENT("()");
+
+ try
+ {
+ EGLDisplay dpy = egl::getCurrentDisplay();
+
+ return egl::success(dpy);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_NO_DISPLAY);
+ }
+}
+
+EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
+ dpy, ctx, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ gl::Context *context = static_cast<gl::Context*>(ctx);
+
+ if (!validateContext(display, context))
+ {
+ return EGL_FALSE;
+ }
+
+ UNIMPLEMENTED(); // FIXME
+
+ return egl::success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglWaitGL(void)
+{
+ EVENT("()");
+
+ try
+ {
+ UNIMPLEMENTED(); // FIXME
+
+ return egl::success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglWaitNative(EGLint engine)
+{
+ EVENT("(EGLint engine = %d)", engine);
+
+ try
+ {
+ UNIMPLEMENTED(); // FIXME
+
+ return egl::success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = (egl::Surface*)surface;
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (display->getRenderer()->isDeviceLost())
+ {
+ return egl::error(EGL_CONTEXT_LOST, EGL_FALSE);
+ }
+
+ if (surface == EGL_NO_SURFACE)
+ {
+ return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ if (eglSurface->swap())
+ {
+ return egl::success(EGL_TRUE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = 0x%0.8p)", dpy, surface, target);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (display->getRenderer()->isDeviceLost())
+ {
+ return egl::error(EGL_CONTEXT_LOST, EGL_FALSE);
+ }
+
+ UNIMPLEMENTED(); // FIXME
+
+ return egl::success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+}
+
+EGLBoolean __stdcall eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint x = %d, EGLint y = %d, EGLint width = %d, EGLint height = %d)", dpy, surface, x, y, width, height);
+
+ try
+ {
+ if (x < 0 || y < 0 || width < 0 || height < 0)
+ {
+ return egl::error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (display->getRenderer()->isDeviceLost())
+ {
+ return egl::error(EGL_CONTEXT_LOST, EGL_FALSE);
+ }
+
+ if (surface == EGL_NO_SURFACE)
+ {
+ return egl::error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ if (eglSurface->postSubBuffer(x, y, width, height))
+ {
+ return egl::success(EGL_TRUE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+__eglMustCastToProperFunctionPointerType __stdcall eglGetProcAddress(const char *procname)
+{
+ EVENT("(const char *procname = \"%s\")", procname);
+
+ try
+ {
+ struct Extension
+ {
+ const char *name;
+ __eglMustCastToProperFunctionPointerType address;
+ };
+
+ static const Extension eglExtensions[] =
+ {
+ {"eglQuerySurfacePointerANGLE", (__eglMustCastToProperFunctionPointerType)eglQuerySurfacePointerANGLE},
+ {"eglPostSubBufferNV", (__eglMustCastToProperFunctionPointerType)eglPostSubBufferNV},
+ {"", NULL},
+ };
+
+ for (unsigned int ext = 0; ext < ArraySize(eglExtensions); ext++)
+ {
+ if (strcmp(procname, eglExtensions[ext].name) == 0)
+ {
+ return (__eglMustCastToProperFunctionPointerType)eglExtensions[ext].address;
+ }
+ }
+
+ return glGetProcAddress(procname);
+ }
+ catch(std::bad_alloc&)
+ {
+ return egl::error(EGL_BAD_ALLOC, (__eglMustCastToProperFunctionPointerType)NULL);
+ }
+}
+}
diff --git a/src/libEGL/libEGL.def b/src/libEGL/libEGL.def
new file mode 100644
index 00000000..71a5e679
--- /dev/null
+++ b/src/libEGL/libEGL.def
@@ -0,0 +1,36 @@
+LIBRARY libEGL
+EXPORTS
+ eglBindAPI @14
+ eglBindTexImage @20
+ eglChooseConfig @7
+ eglCopyBuffers @33
+ eglCreateContext @23
+ eglCreatePbufferFromClientBuffer @18
+ eglCreatePbufferSurface @10
+ eglCreatePixmapSurface @11
+ eglCreateWindowSurface @9
+ eglDestroyContext @24
+ eglDestroySurface @12
+ eglGetConfigAttrib @8
+ eglGetConfigs @6
+ eglGetCurrentContext @26
+ eglGetCurrentDisplay @28
+ eglGetCurrentSurface @27
+ eglGetDisplay @2
+ eglGetError @1
+ eglGetProcAddress @34
+ eglInitialize @3
+ eglMakeCurrent @25
+ eglQueryAPI @15
+ eglQueryContext @29
+ eglQueryString @5
+ eglQuerySurface @13
+ eglReleaseTexImage @21
+ eglReleaseThread @17
+ eglSurfaceAttrib @19
+ eglSwapBuffers @32
+ eglSwapInterval @22
+ eglTerminate @4
+ eglWaitClient @16
+ eglWaitGL @30
+ eglWaitNative @31 \ No newline at end of file
diff --git a/src/libEGL/libEGL.rc b/src/libEGL/libEGL.rc
new file mode 100644
index 00000000..5d1f32f1
--- /dev/null
+++ b/src/libEGL/libEGL.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+#include "../common/version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "#include ""../common/version.h""\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "ANGLE libEGL Dynamic Link Library"
+ VALUE "FileVersion", VERSION_STRING
+ VALUE "InternalName", "libEGL"
+ VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc."
+ VALUE "OriginalFilename", "libEGL.dll"
+ VALUE "PrivateBuild", VERSION_STRING
+ VALUE "ProductName", "ANGLE libEGL Dynamic Link Library"
+ VALUE "ProductVersion", VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/src/libEGL/libEGL.vcxproj b/src/libEGL/libEGL.vcxproj
new file mode 100644
index 00000000..b6bc1efb
--- /dev/null
+++ b/src/libEGL/libEGL.vcxproj
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}</ProjectGuid>
+ <RootNamespace>libEGL</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LibraryPath)</LibraryPath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(DXSDK_DIR)\lib\x86;$(LibraryPath)</LibraryPath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LibraryPath)</LibraryPath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LibraryPath)</LibraryPath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(DXSDK_DIR)\include;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include;</IncludePath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir)/..; $(ProjectDir)/../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBEGL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>libEGL.def</ModuleDefinitionFile>
+ <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>%40echo on
+mkdir "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libEGL.dll" "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libEGL.lib" "$(ProjectDir)..\..\lib\$(Configuration)\"
+%40echo off
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>$(ProjectDir)/..; $(ProjectDir)/../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>ANGLE_DISABLE_TRACE;WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBEGL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>libEGL.def</ModuleDefinitionFile>
+ <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>%40echo on
+mkdir "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libEGL.dll" "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libEGL.lib" "$(ProjectDir)..\..\lib\$(Configuration)\"
+%40echo off
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir)/..; $(ProjectDir)/../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBEGL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>libEGL.def</ModuleDefinitionFile>
+ <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>%40echo on
+mkdir "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libEGL.dll" "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libEGL.lib" "$(ProjectDir)..\..\lib\$(Configuration)\"
+%40echo off
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>$(ProjectDir)/..; $(ProjectDir)/../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBEGL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>libEGL.def</ModuleDefinitionFile>
+ <DelayLoadDLLs>%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>%40echo on
+mkdir "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libEGL.dll" "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libEGL.lib" "$(ProjectDir)..\..\lib\$(Configuration)\"
+%40echo off
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="Config.cpp" />
+ <ClCompile Include="..\Common\debug.cpp" />
+ <ClCompile Include="Display.cpp" />
+ <ClCompile Include="libEGL.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="Surface.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="Config.h" />
+ <ClInclude Include="Display.h" />
+ <ClInclude Include="..\..\include\EGL\egl.h" />
+ <ClInclude Include="..\..\include\EGL\eglext.h" />
+ <ClInclude Include="..\..\include\EGL\eglplatform.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="Surface.h" />
+ <ClInclude Include="..\common\version.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libEGL.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="libEGL.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\libGLESv2\libGLESv2.vcxproj">
+ <Project>{b5871a7a-968c-42e3-a33b-981e6f448e78}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/libEGL/libEGL.vcxproj.filters b/src/libEGL/libEGL.vcxproj.filters
new file mode 100644
index 00000000..860e1690
--- /dev/null
+++ b/src/libEGL/libEGL.vcxproj.filters
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Config.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Common\debug.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Display.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="libEGL.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Surface.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="Config.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Display.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\EGL\egl.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\EGL\eglext.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\EGL\eglplatform.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Surface.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="libEGL.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libEGL.def" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/libEGL/main.cpp b/src/libEGL/main.cpp
new file mode 100644
index 00000000..424ec3fc
--- /dev/null
+++ b/src/libEGL/main.cpp
@@ -0,0 +1,166 @@
+//
+// 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.
+//
+
+// main.cpp: DLL entry point and management of thread-local data.
+
+#include "libEGL/main.h"
+
+#include "common/debug.h"
+
+static DWORD currentTLS = TLS_OUT_OF_INDEXES;
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
+{
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+#if !defined(ANGLE_DISABLE_TRACE)
+ FILE *debug = fopen(TRACE_OUTPUT_FILE, "rt");
+
+ if (debug)
+ {
+ fclose(debug);
+ debug = fopen(TRACE_OUTPUT_FILE, "wt"); // Erase
+
+ if (debug)
+ {
+ fclose(debug);
+ }
+ }
+#endif
+
+ currentTLS = TlsAlloc();
+
+ if (currentTLS == TLS_OUT_OF_INDEXES)
+ {
+ return FALSE;
+ }
+ }
+ // Fall throught to initialize index
+ case DLL_THREAD_ATTACH:
+ {
+ egl::Current *current = (egl::Current*)LocalAlloc(LPTR, sizeof(egl::Current));
+
+ if (current)
+ {
+ TlsSetValue(currentTLS, current);
+
+ current->error = EGL_SUCCESS;
+ current->API = EGL_OPENGL_ES_API;
+ current->display = EGL_NO_DISPLAY;
+ current->drawSurface = EGL_NO_SURFACE;
+ current->readSurface = EGL_NO_SURFACE;
+ }
+ }
+ break;
+ case DLL_THREAD_DETACH:
+ {
+ void *current = TlsGetValue(currentTLS);
+
+ if (current)
+ {
+ LocalFree((HLOCAL)current);
+ }
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+ {
+ void *current = TlsGetValue(currentTLS);
+
+ if (current)
+ {
+ LocalFree((HLOCAL)current);
+ }
+
+ TlsFree(currentTLS);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+namespace egl
+{
+void setCurrentError(EGLint error)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->error = error;
+}
+
+EGLint getCurrentError()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->error;
+}
+
+void setCurrentAPI(EGLenum API)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->API = API;
+}
+
+EGLenum getCurrentAPI()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->API;
+}
+
+void setCurrentDisplay(EGLDisplay dpy)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->display = dpy;
+}
+
+EGLDisplay getCurrentDisplay()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->display;
+}
+
+void setCurrentDrawSurface(EGLSurface surface)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->drawSurface = surface;
+}
+
+EGLSurface getCurrentDrawSurface()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->drawSurface;
+}
+
+void setCurrentReadSurface(EGLSurface surface)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->readSurface = surface;
+}
+
+EGLSurface getCurrentReadSurface()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->readSurface;
+}
+
+void error(EGLint errorCode)
+{
+ egl::setCurrentError(errorCode);
+}
+
+}
diff --git a/src/libEGL/main.h b/src/libEGL/main.h
new file mode 100644
index 00000000..77da8f0f
--- /dev/null
+++ b/src/libEGL/main.h
@@ -0,0 +1,62 @@
+//
+// 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.
+//
+
+// main.h: Management of thread-local data.
+
+#ifndef LIBEGL_MAIN_H_
+#define LIBEGL_MAIN_H_
+
+#define EGLAPI
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+namespace egl
+{
+struct Current
+{
+ EGLint error;
+ EGLenum API;
+ EGLDisplay display;
+ EGLSurface drawSurface;
+ EGLSurface readSurface;
+};
+
+void setCurrentError(EGLint error);
+EGLint getCurrentError();
+
+void setCurrentAPI(EGLenum API);
+EGLenum getCurrentAPI();
+
+void setCurrentDisplay(EGLDisplay dpy);
+EGLDisplay getCurrentDisplay();
+
+void setCurrentDrawSurface(EGLSurface surface);
+EGLSurface getCurrentDrawSurface();
+
+void setCurrentReadSurface(EGLSurface surface);
+EGLSurface getCurrentReadSurface();
+
+void error(EGLint errorCode);
+
+template<class T>
+const T &error(EGLint errorCode, const T &returnValue)
+{
+ error(errorCode);
+
+ return returnValue;
+}
+
+template<class T>
+const T &success(const T &returnValue)
+{
+ egl::setCurrentError(EGL_SUCCESS);
+
+ return returnValue;
+}
+
+}
+
+#endif // LIBEGL_MAIN_H_
diff --git a/src/libEGL/resource.h b/src/libEGL/resource.h
new file mode 100644
index 00000000..3921f4c0
--- /dev/null
+++ b/src/libEGL/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by libEGL.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/libGLESv2/BinaryStream.h b/src/libGLESv2/BinaryStream.h
new file mode 100644
index 00000000..21c2f86c
--- /dev/null
+++ b/src/libGLESv2/BinaryStream.h
@@ -0,0 +1,164 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// BinaryStream.h: Provides binary serialization of simple types.
+
+#ifndef LIBGLESV2_BINARYSTREAM_H_
+#define LIBGLESV2_BINARYSTREAM_H_
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+
+class BinaryInputStream
+{
+ public:
+ BinaryInputStream(const void *data, size_t length)
+ {
+ mError = false;
+ mOffset = 0;
+ mData = static_cast<const char*>(data);
+ mLength = length;
+ }
+
+ template <typename T>
+ void read(T *v, size_t num)
+ {
+ union
+ {
+ T dummy; // Compilation error for non-trivial types
+ } dummy;
+ (void) dummy;
+
+ if (mError)
+ {
+ return;
+ }
+
+ size_t length = num * sizeof(T);
+
+ if (mOffset + length > mLength)
+ {
+ mError = true;
+ return;
+ }
+
+ memcpy(v, mData + mOffset, length);
+ mOffset += length;
+ }
+
+ template <typename T>
+ void read(T * v)
+ {
+ read(v, 1);
+ }
+
+ void read(std::string *v)
+ {
+ size_t length;
+ read(&length);
+
+ if (mError)
+ {
+ return;
+ }
+
+ if (mOffset + length > mLength)
+ {
+ mError = true;
+ return;
+ }
+
+ v->assign(mData + mOffset, length);
+ mOffset += length;
+ }
+
+ void skip(size_t length)
+ {
+ if (mOffset + length > mLength)
+ {
+ mError = true;
+ return;
+ }
+
+ mOffset += length;
+ }
+
+ size_t offset() const
+ {
+ return mOffset;
+ }
+
+ bool error() const
+ {
+ return mError;
+ }
+
+ bool endOfStream() const
+ {
+ return mOffset == mLength;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BinaryInputStream);
+ bool mError;
+ size_t mOffset;
+ const char *mData;
+ size_t mLength;
+};
+
+class BinaryOutputStream
+{
+ public:
+ BinaryOutputStream()
+ {
+ }
+
+ template <typename T>
+ void write(const T *v, size_t num)
+ {
+ union
+ {
+ T dummy; // Compilation error for non-trivial types
+ } dummy;
+ (void) dummy;
+
+ const char *asBytes = reinterpret_cast<const char*>(v);
+ mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T));
+ }
+
+ template <typename T>
+ void write(const T &v)
+ {
+ write(&v, 1);
+ }
+
+ void write(const std::string &v)
+ {
+ size_t length = v.length();
+ write(length);
+
+ write(v.c_str(), length);
+ }
+
+ size_t length() const
+ {
+ return mData.size();
+ }
+
+ const void* data() const
+ {
+ return mData.size() ? &mData[0] : NULL;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BinaryOutputStream);
+ std::vector<char> mData;
+};
+}
+
+#endif // LIBGLESV2_BINARYSTREAM_H_
diff --git a/src/libGLESv2/Buffer.cpp b/src/libGLESv2/Buffer.cpp
new file mode 100644
index 00000000..a64fbad4
--- /dev/null
+++ b/src/libGLESv2/Buffer.cpp
@@ -0,0 +1,126 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// Buffer.cpp: Implements the gl::Buffer class, representing storage of vertex and/or
+// index data. Implements GL buffer objects and related functionality.
+// [OpenGL ES 2.0.24] section 2.9 page 21.
+
+#include "libGLESv2/Buffer.h"
+
+#include "libGLESv2/renderer/VertexBuffer.h"
+#include "libGLESv2/renderer/IndexBuffer.h"
+#include "libGLESv2/renderer/BufferStorage.h"
+#include "libGLESv2/renderer/Renderer.h"
+
+namespace gl
+{
+
+Buffer::Buffer(rx::Renderer *renderer, GLuint id) : RefCountObject(id)
+{
+ mRenderer = renderer;
+ mUsage = GL_DYNAMIC_DRAW;
+
+ mBufferStorage = renderer->createBufferStorage();
+ mStaticVertexBuffer = NULL;
+ mStaticIndexBuffer = NULL;
+ mUnmodifiedDataUse = 0;
+}
+
+Buffer::~Buffer()
+{
+ delete mBufferStorage;
+ delete mStaticVertexBuffer;
+ delete mStaticIndexBuffer;
+}
+
+void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage)
+{
+ mBufferStorage->clear();
+ mIndexRangeCache.clear();
+ mBufferStorage->setData(data, size, 0);
+
+ mUsage = usage;
+
+ invalidateStaticData();
+
+ if (usage == GL_STATIC_DRAW)
+ {
+ mStaticVertexBuffer = new rx::StaticVertexBufferInterface(mRenderer);
+ mStaticIndexBuffer = new rx::StaticIndexBufferInterface(mRenderer);
+ }
+}
+
+void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset)
+{
+ mBufferStorage->setData(data, size, offset);
+ mIndexRangeCache.invalidateRange(offset, size);
+
+ if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0))
+ {
+ invalidateStaticData();
+ }
+
+ mUnmodifiedDataUse = 0;
+}
+
+rx::BufferStorage *Buffer::getStorage() const
+{
+ return mBufferStorage;
+}
+
+unsigned int Buffer::size()
+{
+ return mBufferStorage->getSize();
+}
+
+GLenum Buffer::usage() const
+{
+ return mUsage;
+}
+
+rx::StaticVertexBufferInterface *Buffer::getStaticVertexBuffer()
+{
+ return mStaticVertexBuffer;
+}
+
+rx::StaticIndexBufferInterface *Buffer::getStaticIndexBuffer()
+{
+ return mStaticIndexBuffer;
+}
+
+void Buffer::invalidateStaticData()
+{
+ delete mStaticVertexBuffer;
+ mStaticVertexBuffer = NULL;
+
+ delete mStaticIndexBuffer;
+ mStaticIndexBuffer = NULL;
+
+ mUnmodifiedDataUse = 0;
+}
+
+// Creates static buffers if sufficient used data has been left unmodified
+void Buffer::promoteStaticUsage(int dataSize)
+{
+ if (!mStaticVertexBuffer && !mStaticIndexBuffer)
+ {
+ mUnmodifiedDataUse += dataSize;
+
+ if (mUnmodifiedDataUse > 3 * mBufferStorage->getSize())
+ {
+ mStaticVertexBuffer = new rx::StaticVertexBufferInterface(mRenderer);
+ mStaticIndexBuffer = new rx::StaticIndexBufferInterface(mRenderer);
+ }
+ }
+}
+
+rx::IndexRangeCache *Buffer::getIndexRangeCache()
+{
+ return &mIndexRangeCache;
+}
+
+}
diff --git a/src/libGLESv2/Buffer.h b/src/libGLESv2/Buffer.h
new file mode 100644
index 00000000..3f9fe8f8
--- /dev/null
+++ b/src/libGLESv2/Buffer.h
@@ -0,0 +1,68 @@
+//
+// 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.
+//
+
+// Buffer.h: Defines the gl::Buffer class, representing storage of vertex and/or
+// index data. Implements GL buffer objects and related functionality.
+// [OpenGL ES 2.0.24] section 2.9 page 21.
+
+#ifndef LIBGLESV2_BUFFER_H_
+#define LIBGLESV2_BUFFER_H_
+
+#include "common/angleutils.h"
+#include "common/RefCountObject.h"
+#include "libGLESv2/renderer/IndexRangeCache.h"
+
+namespace rx
+{
+class Renderer;
+class BufferStorage;
+class StaticIndexBufferInterface;
+class StaticVertexBufferInterface;
+};
+
+namespace gl
+{
+
+class Buffer : public RefCountObject
+{
+ public:
+ Buffer(rx::Renderer *renderer, GLuint id);
+
+ virtual ~Buffer();
+
+ void bufferData(const void *data, GLsizeiptr size, GLenum usage);
+ void bufferSubData(const void *data, GLsizeiptr size, GLintptr offset);
+
+ GLenum usage() const;
+
+ rx::BufferStorage *getStorage() const;
+ unsigned int size();
+
+ rx::StaticVertexBufferInterface *getStaticVertexBuffer();
+ rx::StaticIndexBufferInterface *getStaticIndexBuffer();
+ void invalidateStaticData();
+ void promoteStaticUsage(int dataSize);
+
+ rx::IndexRangeCache *getIndexRangeCache();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Buffer);
+
+ rx::Renderer *mRenderer;
+ GLenum mUsage;
+
+ rx::BufferStorage *mBufferStorage;
+
+ rx::IndexRangeCache mIndexRangeCache;
+
+ rx::StaticVertexBufferInterface *mStaticVertexBuffer;
+ rx::StaticIndexBufferInterface *mStaticIndexBuffer;
+ unsigned int mUnmodifiedDataUse;
+};
+
+}
+
+#endif // LIBGLESV2_BUFFER_H_
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
new file mode 100644
index 00000000..e084db1a
--- /dev/null
+++ b/src/libGLESv2/Context.cpp
@@ -0,0 +1,2972 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// Context.cpp: Implements the gl::Context class, managing all GL state and performing
+// rendering operations. It is the GLES2 specific implementation of EGLContext.
+
+#include "libGLESv2/Context.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/Fence.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/Query.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/ResourceManager.h"
+#include "libGLESv2/renderer/IndexDataManager.h"
+#include "libGLESv2/renderer/RenderTarget.h"
+#include "libGLESv2/renderer/Renderer.h"
+
+#include "libEGL/Surface.h"
+
+#undef near
+#undef far
+
+namespace gl
+{
+static const char* makeStaticString(const std::string& str)
+{
+ static std::set<std::string> strings;
+ std::set<std::string>::iterator it = strings.find(str);
+ if (it != strings.end())
+ return it->c_str();
+
+ return strings.insert(str).first->c_str();
+}
+
+Context::Context(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) : mRenderer(renderer)
+{
+ ASSERT(robustAccess == false); // Unimplemented
+
+ mFenceHandleAllocator.setBaseHandle(0);
+
+ setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ mState.depthClearValue = 1.0f;
+ mState.stencilClearValue = 0;
+
+ mState.rasterizer.cullFace = false;
+ mState.rasterizer.cullMode = GL_BACK;
+ mState.rasterizer.frontFace = GL_CCW;
+ mState.rasterizer.polygonOffsetFill = false;
+ mState.rasterizer.polygonOffsetFactor = 0.0f;
+ mState.rasterizer.polygonOffsetUnits = 0.0f;
+ mState.rasterizer.pointDrawMode = false;
+ mState.rasterizer.multiSample = false;
+ mState.scissorTest = false;
+ mState.scissor.x = 0;
+ mState.scissor.y = 0;
+ mState.scissor.width = 0;
+ mState.scissor.height = 0;
+
+ mState.blend.blend = false;
+ mState.blend.sourceBlendRGB = GL_ONE;
+ mState.blend.sourceBlendAlpha = GL_ONE;
+ mState.blend.destBlendRGB = GL_ZERO;
+ mState.blend.destBlendAlpha = GL_ZERO;
+ mState.blend.blendEquationRGB = GL_FUNC_ADD;
+ mState.blend.blendEquationAlpha = GL_FUNC_ADD;
+ mState.blend.sampleAlphaToCoverage = false;
+ mState.blend.dither = true;
+
+ mState.blendColor.red = 0;
+ mState.blendColor.green = 0;
+ mState.blendColor.blue = 0;
+ mState.blendColor.alpha = 0;
+
+ mState.depthStencil.depthTest = false;
+ mState.depthStencil.depthFunc = GL_LESS;
+ mState.depthStencil.depthMask = true;
+ mState.depthStencil.stencilTest = false;
+ mState.depthStencil.stencilFunc = GL_ALWAYS;
+ mState.depthStencil.stencilMask = -1;
+ mState.depthStencil.stencilWritemask = -1;
+ mState.depthStencil.stencilBackFunc = GL_ALWAYS;
+ mState.depthStencil.stencilBackMask = - 1;
+ mState.depthStencil.stencilBackWritemask = -1;
+ mState.depthStencil.stencilFail = GL_KEEP;
+ mState.depthStencil.stencilPassDepthFail = GL_KEEP;
+ mState.depthStencil.stencilPassDepthPass = GL_KEEP;
+ mState.depthStencil.stencilBackFail = GL_KEEP;
+ mState.depthStencil.stencilBackPassDepthFail = GL_KEEP;
+ mState.depthStencil.stencilBackPassDepthPass = GL_KEEP;
+
+ mState.stencilRef = 0;
+ mState.stencilBackRef = 0;
+
+ mState.sampleCoverage = false;
+ mState.sampleCoverageValue = 1.0f;
+ mState.sampleCoverageInvert = false;
+ mState.generateMipmapHint = GL_DONT_CARE;
+ mState.fragmentShaderDerivativeHint = GL_DONT_CARE;
+
+ mState.lineWidth = 1.0f;
+
+ mState.viewport.x = 0;
+ mState.viewport.y = 0;
+ mState.viewport.width = 0;
+ mState.viewport.height = 0;
+ mState.zNear = 0.0f;
+ mState.zFar = 1.0f;
+
+ mState.blend.colorMaskRed = true;
+ mState.blend.colorMaskGreen = true;
+ mState.blend.colorMaskBlue = true;
+ mState.blend.colorMaskAlpha = true;
+
+ if (shareContext != NULL)
+ {
+ mResourceManager = shareContext->mResourceManager;
+ mResourceManager->addRef();
+ }
+ else
+ {
+ mResourceManager = new ResourceManager(mRenderer);
+ }
+
+ // [OpenGL ES 2.0.24] section 3.7 page 83:
+ // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional
+ // and cube map texture state vectors respectively associated with them.
+ // In order that access to these initial textures not be lost, they are treated as texture
+ // objects all of whose names are 0.
+
+ mTexture2DZero.set(new Texture2D(mRenderer, 0));
+ mTextureCubeMapZero.set(new TextureCubeMap(mRenderer, 0));
+
+ mState.activeSampler = 0;
+ bindArrayBuffer(0);
+ bindElementArrayBuffer(0);
+ bindTextureCubeMap(0);
+ bindTexture2D(0);
+ bindReadFramebuffer(0);
+ bindDrawFramebuffer(0);
+ bindRenderbuffer(0);
+
+ mState.currentProgram = 0;
+ mCurrentProgramBinary.set(NULL);
+
+ mState.packAlignment = 4;
+ mState.unpackAlignment = 4;
+ mState.packReverseRowOrder = false;
+
+ mExtensionString = NULL;
+ mRendererString = NULL;
+
+ mInvalidEnum = false;
+ mInvalidValue = false;
+ mInvalidOperation = false;
+ mOutOfMemory = false;
+ mInvalidFramebufferOperation = false;
+
+ mHasBeenCurrent = false;
+ mContextLost = false;
+ mResetStatus = GL_NO_ERROR;
+ mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT);
+ mRobustAccess = robustAccess;
+
+ mSupportsBGRATextures = false;
+ mSupportsDXT1Textures = false;
+ mSupportsDXT3Textures = false;
+ mSupportsDXT5Textures = false;
+ mSupportsEventQueries = false;
+ mSupportsOcclusionQueries = false;
+ mNumCompressedTextureFormats = 0;
+}
+
+Context::~Context()
+{
+ if (mState.currentProgram != 0)
+ {
+ Program *programObject = mResourceManager->getProgram(mState.currentProgram);
+ if (programObject)
+ {
+ programObject->release();
+ }
+ mState.currentProgram = 0;
+ }
+ mCurrentProgramBinary.set(NULL);
+
+ while (!mFramebufferMap.empty())
+ {
+ deleteFramebuffer(mFramebufferMap.begin()->first);
+ }
+
+ while (!mFenceMap.empty())
+ {
+ deleteFence(mFenceMap.begin()->first);
+ }
+
+ while (!mQueryMap.empty())
+ {
+ deleteQuery(mQueryMap.begin()->first);
+ }
+
+ for (int type = 0; type < TEXTURE_TYPE_COUNT; type++)
+ {
+ for (int sampler = 0; sampler < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++)
+ {
+ mState.samplerTexture[type][sampler].set(NULL);
+ }
+ }
+
+ for (int type = 0; type < TEXTURE_TYPE_COUNT; type++)
+ {
+ mIncompleteTextures[type].set(NULL);
+ }
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mState.vertexAttribute[i].mBoundBuffer.set(NULL);
+ }
+
+ for (int i = 0; i < QUERY_TYPE_COUNT; i++)
+ {
+ mState.activeQuery[i].set(NULL);
+ }
+
+ mState.arrayBuffer.set(NULL);
+ mState.elementArrayBuffer.set(NULL);
+ mState.renderbuffer.set(NULL);
+
+ mTexture2DZero.set(NULL);
+ mTextureCubeMapZero.set(NULL);
+
+ mResourceManager->release();
+}
+
+void Context::makeCurrent(egl::Surface *surface)
+{
+ if (!mHasBeenCurrent)
+ {
+ mMajorShaderModel = mRenderer->getMajorShaderModel();
+ mMaximumPointSize = mRenderer->getMaxPointSize();
+ mSupportsVertexTexture = mRenderer->getVertexTextureSupport();
+ mSupportsNonPower2Texture = mRenderer->getNonPower2TextureSupport();
+ mSupportsInstancing = mRenderer->getInstancingSupport();
+
+ mMaxViewportDimension = mRenderer->getMaxViewportDimension();
+ mMaxTextureDimension = std::min(std::min(mRenderer->getMaxTextureWidth(), mRenderer->getMaxTextureHeight()),
+ (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE);
+ mMaxCubeTextureDimension = std::min(mMaxTextureDimension, (int)gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE);
+ mMaxRenderbufferDimension = mMaxTextureDimension;
+ mMaxTextureLevel = log2(mMaxTextureDimension) + 1;
+ mMaxTextureAnisotropy = mRenderer->getTextureMaxAnisotropy();
+ TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d, MaxTextureAnisotropy=%f",
+ mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel, mMaxTextureAnisotropy);
+
+ mSupportsEventQueries = mRenderer->getEventQuerySupport();
+ mSupportsOcclusionQueries = mRenderer->getOcclusionQuerySupport();
+ mSupportsBGRATextures = mRenderer->getBGRATextureSupport();
+ mSupportsDXT1Textures = mRenderer->getDXT1TextureSupport();
+ mSupportsDXT3Textures = mRenderer->getDXT3TextureSupport();
+ mSupportsDXT5Textures = mRenderer->getDXT5TextureSupport();
+ mSupportsFloat32Textures = mRenderer->getFloat32TextureSupport(&mSupportsFloat32LinearFilter, &mSupportsFloat32RenderableTextures);
+ mSupportsFloat16Textures = mRenderer->getFloat16TextureSupport(&mSupportsFloat16LinearFilter, &mSupportsFloat16RenderableTextures);
+ mSupportsLuminanceTextures = mRenderer->getLuminanceTextureSupport();
+ mSupportsLuminanceAlphaTextures = mRenderer->getLuminanceAlphaTextureSupport();
+ mSupportsDepthTextures = mRenderer->getDepthTextureSupport();
+ mSupportsTextureFilterAnisotropy = mRenderer->getTextureFilterAnisotropySupport();
+ mSupports32bitIndices = mRenderer->get32BitIndexSupport();
+
+ mNumCompressedTextureFormats = 0;
+ if (supportsDXT1Textures())
+ {
+ mNumCompressedTextureFormats += 2;
+ }
+ if (supportsDXT3Textures())
+ {
+ mNumCompressedTextureFormats += 1;
+ }
+ if (supportsDXT5Textures())
+ {
+ mNumCompressedTextureFormats += 1;
+ }
+
+ initExtensionString();
+ initRendererString();
+
+ mState.viewport.x = 0;
+ mState.viewport.y = 0;
+ mState.viewport.width = surface->getWidth();
+ mState.viewport.height = surface->getHeight();
+
+ mState.scissor.x = 0;
+ mState.scissor.y = 0;
+ mState.scissor.width = surface->getWidth();
+ mState.scissor.height = surface->getHeight();
+
+ mHasBeenCurrent = true;
+ }
+
+ // Wrap the existing swapchain resources into GL objects and assign them to the '0' names
+ rx::SwapChain *swapchain = surface->getSwapChain();
+
+ Colorbuffer *colorbufferZero = new Colorbuffer(mRenderer, swapchain);
+ DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(mRenderer, swapchain);
+ Framebuffer *framebufferZero = new DefaultFramebuffer(mRenderer, colorbufferZero, depthStencilbufferZero);
+
+ setFramebufferZero(framebufferZero);
+}
+
+// NOTE: this function should not assume that this context is current!
+void Context::markContextLost()
+{
+ if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT)
+ mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT;
+ mContextLost = true;
+}
+
+bool Context::isContextLost()
+{
+ return mContextLost;
+}
+
+void Context::setClearColor(float red, float green, float blue, float alpha)
+{
+ mState.colorClearValue.red = red;
+ mState.colorClearValue.green = green;
+ mState.colorClearValue.blue = blue;
+ mState.colorClearValue.alpha = alpha;
+}
+
+void Context::setClearDepth(float depth)
+{
+ mState.depthClearValue = depth;
+}
+
+void Context::setClearStencil(int stencil)
+{
+ mState.stencilClearValue = stencil;
+}
+
+void Context::setCullFace(bool enabled)
+{
+ mState.rasterizer.cullFace = enabled;
+}
+
+bool Context::isCullFaceEnabled() const
+{
+ return mState.rasterizer.cullFace;
+}
+
+void Context::setCullMode(GLenum mode)
+{
+ mState.rasterizer.cullMode = mode;
+}
+
+void Context::setFrontFace(GLenum front)
+{
+ mState.rasterizer.frontFace = front;
+}
+
+void Context::setDepthTest(bool enabled)
+{
+ mState.depthStencil.depthTest = enabled;
+}
+
+bool Context::isDepthTestEnabled() const
+{
+ return mState.depthStencil.depthTest;
+}
+
+void Context::setDepthFunc(GLenum depthFunc)
+{
+ mState.depthStencil.depthFunc = depthFunc;
+}
+
+void Context::setDepthRange(float zNear, float zFar)
+{
+ mState.zNear = zNear;
+ mState.zFar = zFar;
+}
+
+void Context::setBlend(bool enabled)
+{
+ mState.blend.blend = enabled;
+}
+
+bool Context::isBlendEnabled() const
+{
+ return mState.blend.blend;
+}
+
+void Context::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha)
+{
+ mState.blend.sourceBlendRGB = sourceRGB;
+ mState.blend.destBlendRGB = destRGB;
+ mState.blend.sourceBlendAlpha = sourceAlpha;
+ mState.blend.destBlendAlpha = destAlpha;
+}
+
+void Context::setBlendColor(float red, float green, float blue, float alpha)
+{
+ mState.blendColor.red = red;
+ mState.blendColor.green = green;
+ mState.blendColor.blue = blue;
+ mState.blendColor.alpha = alpha;
+}
+
+void Context::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation)
+{
+ mState.blend.blendEquationRGB = rgbEquation;
+ mState.blend.blendEquationAlpha = alphaEquation;
+}
+
+void Context::setStencilTest(bool enabled)
+{
+ mState.depthStencil.stencilTest = enabled;
+}
+
+bool Context::isStencilTestEnabled() const
+{
+ return mState.depthStencil.stencilTest;
+}
+
+void Context::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask)
+{
+ mState.depthStencil.stencilFunc = stencilFunc;
+ mState.stencilRef = (stencilRef > 0) ? stencilRef : 0;
+ mState.depthStencil.stencilMask = stencilMask;
+}
+
+void Context::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask)
+{
+ mState.depthStencil.stencilBackFunc = stencilBackFunc;
+ mState.stencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0;
+ mState.depthStencil.stencilBackMask = stencilBackMask;
+}
+
+void Context::setStencilWritemask(GLuint stencilWritemask)
+{
+ mState.depthStencil.stencilWritemask = stencilWritemask;
+}
+
+void Context::setStencilBackWritemask(GLuint stencilBackWritemask)
+{
+ mState.depthStencil.stencilBackWritemask = stencilBackWritemask;
+}
+
+void Context::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass)
+{
+ mState.depthStencil.stencilFail = stencilFail;
+ mState.depthStencil.stencilPassDepthFail = stencilPassDepthFail;
+ mState.depthStencil.stencilPassDepthPass = stencilPassDepthPass;
+}
+
+void Context::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass)
+{
+ mState.depthStencil.stencilBackFail = stencilBackFail;
+ mState.depthStencil.stencilBackPassDepthFail = stencilBackPassDepthFail;
+ mState.depthStencil.stencilBackPassDepthPass = stencilBackPassDepthPass;
+}
+
+void Context::setPolygonOffsetFill(bool enabled)
+{
+ mState.rasterizer.polygonOffsetFill = enabled;
+}
+
+bool Context::isPolygonOffsetFillEnabled() const
+{
+ return mState.rasterizer.polygonOffsetFill;
+}
+
+void Context::setPolygonOffsetParams(GLfloat factor, GLfloat units)
+{
+ // An application can pass NaN values here, so handle this gracefully
+ mState.rasterizer.polygonOffsetFactor = factor != factor ? 0.0f : factor;
+ mState.rasterizer.polygonOffsetUnits = units != units ? 0.0f : units;
+}
+
+void Context::setSampleAlphaToCoverage(bool enabled)
+{
+ mState.blend.sampleAlphaToCoverage = enabled;
+}
+
+bool Context::isSampleAlphaToCoverageEnabled() const
+{
+ return mState.blend.sampleAlphaToCoverage;
+}
+
+void Context::setSampleCoverage(bool enabled)
+{
+ mState.sampleCoverage = enabled;
+}
+
+bool Context::isSampleCoverageEnabled() const
+{
+ return mState.sampleCoverage;
+}
+
+void Context::setSampleCoverageParams(GLclampf value, bool invert)
+{
+ mState.sampleCoverageValue = value;
+ mState.sampleCoverageInvert = invert;
+}
+
+void Context::setScissorTest(bool enabled)
+{
+ mState.scissorTest = enabled;
+}
+
+bool Context::isScissorTestEnabled() const
+{
+ return mState.scissorTest;
+}
+
+void Context::setDither(bool enabled)
+{
+ mState.blend.dither = enabled;
+}
+
+bool Context::isDitherEnabled() const
+{
+ return mState.blend.dither;
+}
+
+void Context::setLineWidth(GLfloat width)
+{
+ mState.lineWidth = width;
+}
+
+void Context::setGenerateMipmapHint(GLenum hint)
+{
+ mState.generateMipmapHint = hint;
+}
+
+void Context::setFragmentShaderDerivativeHint(GLenum hint)
+{
+ mState.fragmentShaderDerivativeHint = hint;
+ // TODO: Propagate the hint to shader translator so we can write
+ // ddx, ddx_coarse, or ddx_fine depending on the hint.
+ // Ignore for now. It is valid for implementations to ignore hint.
+}
+
+void Context::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ mState.viewport.x = x;
+ mState.viewport.y = y;
+ mState.viewport.width = width;
+ mState.viewport.height = height;
+}
+
+void Context::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ mState.scissor.x = x;
+ mState.scissor.y = y;
+ mState.scissor.width = width;
+ mState.scissor.height = height;
+}
+
+void Context::setColorMask(bool red, bool green, bool blue, bool alpha)
+{
+ mState.blend.colorMaskRed = red;
+ mState.blend.colorMaskGreen = green;
+ mState.blend.colorMaskBlue = blue;
+ mState.blend.colorMaskAlpha = alpha;
+}
+
+void Context::setDepthMask(bool mask)
+{
+ mState.depthStencil.depthMask = mask;
+}
+
+void Context::setActiveSampler(unsigned int active)
+{
+ mState.activeSampler = active;
+}
+
+GLuint Context::getReadFramebufferHandle() const
+{
+ return mState.readFramebuffer;
+}
+
+GLuint Context::getDrawFramebufferHandle() const
+{
+ return mState.drawFramebuffer;
+}
+
+GLuint Context::getRenderbufferHandle() const
+{
+ return mState.renderbuffer.id();
+}
+
+GLuint Context::getArrayBufferHandle() const
+{
+ return mState.arrayBuffer.id();
+}
+
+GLuint Context::getActiveQuery(GLenum target) const
+{
+ Query *queryObject = NULL;
+
+ switch (target)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED].get();
+ break;
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE].get();
+ break;
+ default:
+ ASSERT(false);
+ }
+
+ if (queryObject)
+ {
+ return queryObject->id();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)
+{
+ mState.vertexAttribute[attribNum].mArrayEnabled = enabled;
+}
+
+const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum)
+{
+ return mState.vertexAttribute[attribNum];
+}
+
+void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized,
+ GLsizei stride, const void *pointer)
+{
+ mState.vertexAttribute[attribNum].mBoundBuffer.set(boundBuffer);
+ mState.vertexAttribute[attribNum].mSize = size;
+ mState.vertexAttribute[attribNum].mType = type;
+ mState.vertexAttribute[attribNum].mNormalized = normalized;
+ mState.vertexAttribute[attribNum].mStride = stride;
+ mState.vertexAttribute[attribNum].mPointer = pointer;
+}
+
+const void *Context::getVertexAttribPointer(unsigned int attribNum) const
+{
+ return mState.vertexAttribute[attribNum].mPointer;
+}
+
+void Context::setPackAlignment(GLint alignment)
+{
+ mState.packAlignment = alignment;
+}
+
+GLint Context::getPackAlignment() const
+{
+ return mState.packAlignment;
+}
+
+void Context::setUnpackAlignment(GLint alignment)
+{
+ mState.unpackAlignment = alignment;
+}
+
+GLint Context::getUnpackAlignment() const
+{
+ return mState.unpackAlignment;
+}
+
+void Context::setPackReverseRowOrder(bool reverseRowOrder)
+{
+ mState.packReverseRowOrder = reverseRowOrder;
+}
+
+bool Context::getPackReverseRowOrder() const
+{
+ return mState.packReverseRowOrder;
+}
+
+GLuint Context::createBuffer()
+{
+ return mResourceManager->createBuffer();
+}
+
+GLuint Context::createProgram()
+{
+ return mResourceManager->createProgram();
+}
+
+GLuint Context::createShader(GLenum type)
+{
+ return mResourceManager->createShader(type);
+}
+
+GLuint Context::createTexture()
+{
+ return mResourceManager->createTexture();
+}
+
+GLuint Context::createRenderbuffer()
+{
+ return mResourceManager->createRenderbuffer();
+}
+
+// Returns an unused framebuffer name
+GLuint Context::createFramebuffer()
+{
+ GLuint handle = mFramebufferHandleAllocator.allocate();
+
+ mFramebufferMap[handle] = NULL;
+
+ return handle;
+}
+
+GLuint Context::createFence()
+{
+ GLuint handle = mFenceHandleAllocator.allocate();
+
+ mFenceMap[handle] = new Fence(mRenderer);
+
+ return handle;
+}
+
+// Returns an unused query name
+GLuint Context::createQuery()
+{
+ GLuint handle = mQueryHandleAllocator.allocate();
+
+ mQueryMap[handle] = NULL;
+
+ return handle;
+}
+
+void Context::deleteBuffer(GLuint buffer)
+{
+ if (mResourceManager->getBuffer(buffer))
+ {
+ detachBuffer(buffer);
+ }
+
+ mResourceManager->deleteBuffer(buffer);
+}
+
+void Context::deleteShader(GLuint shader)
+{
+ mResourceManager->deleteShader(shader);
+}
+
+void Context::deleteProgram(GLuint program)
+{
+ mResourceManager->deleteProgram(program);
+}
+
+void Context::deleteTexture(GLuint texture)
+{
+ if (mResourceManager->getTexture(texture))
+ {
+ detachTexture(texture);
+ }
+
+ mResourceManager->deleteTexture(texture);
+}
+
+void Context::deleteRenderbuffer(GLuint renderbuffer)
+{
+ if (mResourceManager->getRenderbuffer(renderbuffer))
+ {
+ detachRenderbuffer(renderbuffer);
+ }
+
+ mResourceManager->deleteRenderbuffer(renderbuffer);
+}
+
+void Context::deleteFramebuffer(GLuint framebuffer)
+{
+ FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer);
+
+ if (framebufferObject != mFramebufferMap.end())
+ {
+ detachFramebuffer(framebuffer);
+
+ mFramebufferHandleAllocator.release(framebufferObject->first);
+ delete framebufferObject->second;
+ mFramebufferMap.erase(framebufferObject);
+ }
+}
+
+void Context::deleteFence(GLuint fence)
+{
+ FenceMap::iterator fenceObject = mFenceMap.find(fence);
+
+ if (fenceObject != mFenceMap.end())
+ {
+ mFenceHandleAllocator.release(fenceObject->first);
+ delete fenceObject->second;
+ mFenceMap.erase(fenceObject);
+ }
+}
+
+void Context::deleteQuery(GLuint query)
+{
+ QueryMap::iterator queryObject = mQueryMap.find(query);
+ if (queryObject != mQueryMap.end())
+ {
+ mQueryHandleAllocator.release(queryObject->first);
+ if (queryObject->second)
+ {
+ queryObject->second->release();
+ }
+ mQueryMap.erase(queryObject);
+ }
+}
+
+Buffer *Context::getBuffer(GLuint handle)
+{
+ return mResourceManager->getBuffer(handle);
+}
+
+Shader *Context::getShader(GLuint handle)
+{
+ return mResourceManager->getShader(handle);
+}
+
+Program *Context::getProgram(GLuint handle)
+{
+ return mResourceManager->getProgram(handle);
+}
+
+Texture *Context::getTexture(GLuint handle)
+{
+ return mResourceManager->getTexture(handle);
+}
+
+Renderbuffer *Context::getRenderbuffer(GLuint handle)
+{
+ return mResourceManager->getRenderbuffer(handle);
+}
+
+Framebuffer *Context::getReadFramebuffer()
+{
+ return getFramebuffer(mState.readFramebuffer);
+}
+
+Framebuffer *Context::getDrawFramebuffer()
+{
+ return mBoundDrawFramebuffer;
+}
+
+void Context::bindArrayBuffer(unsigned int buffer)
+{
+ mResourceManager->checkBufferAllocation(buffer);
+
+ mState.arrayBuffer.set(getBuffer(buffer));
+}
+
+void Context::bindElementArrayBuffer(unsigned int buffer)
+{
+ mResourceManager->checkBufferAllocation(buffer);
+
+ mState.elementArrayBuffer.set(getBuffer(buffer));
+}
+
+void Context::bindTexture2D(GLuint texture)
+{
+ mResourceManager->checkTextureAllocation(texture, TEXTURE_2D);
+
+ mState.samplerTexture[TEXTURE_2D][mState.activeSampler].set(getTexture(texture));
+}
+
+void Context::bindTextureCubeMap(GLuint texture)
+{
+ mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE);
+
+ mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].set(getTexture(texture));
+}
+
+void Context::bindReadFramebuffer(GLuint framebuffer)
+{
+ if (!getFramebuffer(framebuffer))
+ {
+ mFramebufferMap[framebuffer] = new Framebuffer(mRenderer);
+ }
+
+ mState.readFramebuffer = framebuffer;
+}
+
+void Context::bindDrawFramebuffer(GLuint framebuffer)
+{
+ if (!getFramebuffer(framebuffer))
+ {
+ mFramebufferMap[framebuffer] = new Framebuffer(mRenderer);
+ }
+
+ mState.drawFramebuffer = framebuffer;
+
+ mBoundDrawFramebuffer = getFramebuffer(framebuffer);
+}
+
+void Context::bindRenderbuffer(GLuint renderbuffer)
+{
+ mResourceManager->checkRenderbufferAllocation(renderbuffer);
+
+ mState.renderbuffer.set(getRenderbuffer(renderbuffer));
+}
+
+void Context::useProgram(GLuint program)
+{
+ GLuint priorProgram = mState.currentProgram;
+ mState.currentProgram = program; // Must switch before trying to delete, otherwise it only gets flagged.
+
+ if (priorProgram != program)
+ {
+ Program *newProgram = mResourceManager->getProgram(program);
+ Program *oldProgram = mResourceManager->getProgram(priorProgram);
+ mCurrentProgramBinary.set(NULL);
+
+ if (newProgram)
+ {
+ newProgram->addRef();
+ mCurrentProgramBinary.set(newProgram->getProgramBinary());
+ }
+
+ if (oldProgram)
+ {
+ oldProgram->release();
+ }
+ }
+}
+
+void Context::linkProgram(GLuint program)
+{
+ Program *programObject = mResourceManager->getProgram(program);
+
+ bool linked = programObject->link();
+
+ // if the current program was relinked successfully we
+ // need to install the new executables
+ if (linked && program == mState.currentProgram)
+ {
+ mCurrentProgramBinary.set(programObject->getProgramBinary());
+ }
+}
+
+void Context::setProgramBinary(GLuint program, const void *binary, GLint length)
+{
+ Program *programObject = mResourceManager->getProgram(program);
+
+ bool loaded = programObject->setProgramBinary(binary, length);
+
+ // if the current program was reloaded successfully we
+ // need to install the new executables
+ if (loaded && program == mState.currentProgram)
+ {
+ mCurrentProgramBinary.set(programObject->getProgramBinary());
+ }
+
+}
+
+void Context::beginQuery(GLenum target, GLuint query)
+{
+ // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
+ // of zero, if the active query object name for <target> 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 <id> is the name of an
+ // existing query object whose type does not match <target>, or if <id> 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.
+ for (int i = 0; i < QUERY_TYPE_COUNT; i++)
+ {
+ if (mState.activeQuery[i].get() != NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+
+ QueryType qType;
+ switch (target)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ qType = QUERY_ANY_SAMPLES_PASSED;
+ break;
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE;
+ break;
+ default:
+ ASSERT(false);
+ return;
+ }
+
+ Query *queryObject = getQuery(query, true, target);
+
+ // check that name was obtained with glGenQueries
+ if (!queryObject)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ // check for type mismatch
+ if (queryObject->getType() != target)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ // set query as active for specified target
+ mState.activeQuery[qType].set(queryObject);
+
+ // begin query
+ queryObject->begin();
+}
+
+void Context::endQuery(GLenum target)
+{
+ QueryType qType;
+
+ switch (target)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ qType = QUERY_ANY_SAMPLES_PASSED;
+ break;
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE;
+ break;
+ default:
+ ASSERT(false);
+ return;
+ }
+
+ Query *queryObject = mState.activeQuery[qType].get();
+
+ if (queryObject == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ queryObject->end();
+
+ mState.activeQuery[qType].set(NULL);
+}
+
+void Context::setFramebufferZero(Framebuffer *buffer)
+{
+ delete mFramebufferMap[0];
+ mFramebufferMap[0] = buffer;
+ if (mState.drawFramebuffer == 0)
+ {
+ mBoundDrawFramebuffer = buffer;
+ }
+}
+
+void Context::setRenderbufferStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples)
+{
+ RenderbufferStorage *renderbuffer = NULL;
+ switch (internalformat)
+ {
+ case GL_DEPTH_COMPONENT16:
+ renderbuffer = new gl::Depthbuffer(mRenderer, width, height, samples);
+ break;
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ renderbuffer = new gl::Colorbuffer(mRenderer,width, height, internalformat, samples);
+ break;
+ case GL_STENCIL_INDEX8:
+ renderbuffer = new gl::Stencilbuffer(mRenderer, width, height, samples);
+ break;
+ case GL_DEPTH24_STENCIL8_OES:
+ renderbuffer = new gl::DepthStencilbuffer(mRenderer, width, height, samples);
+ break;
+ default:
+ UNREACHABLE(); return;
+ }
+
+ Renderbuffer *renderbufferObject = mState.renderbuffer.get();
+ renderbufferObject->setStorage(renderbuffer);
+}
+
+Framebuffer *Context::getFramebuffer(unsigned int handle)
+{
+ FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle);
+
+ if (framebuffer == mFramebufferMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return framebuffer->second;
+ }
+}
+
+Fence *Context::getFence(unsigned int handle)
+{
+ FenceMap::iterator fence = mFenceMap.find(handle);
+
+ if (fence == mFenceMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return fence->second;
+ }
+}
+
+Query *Context::getQuery(unsigned int handle, bool create, GLenum type)
+{
+ QueryMap::iterator query = mQueryMap.find(handle);
+
+ if (query == mQueryMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ if (!query->second && create)
+ {
+ query->second = new Query(mRenderer, type, handle);
+ query->second->addRef();
+ }
+ return query->second;
+ }
+}
+
+Buffer *Context::getArrayBuffer()
+{
+ return mState.arrayBuffer.get();
+}
+
+Buffer *Context::getElementArrayBuffer()
+{
+ return mState.elementArrayBuffer.get();
+}
+
+ProgramBinary *Context::getCurrentProgramBinary()
+{
+ return mCurrentProgramBinary.get();
+}
+
+Texture2D *Context::getTexture2D()
+{
+ return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D));
+}
+
+TextureCubeMap *Context::getTextureCubeMap()
+{
+ return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE));
+}
+
+Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type)
+{
+ GLuint texid = mState.samplerTexture[type][sampler].id();
+
+ if (texid == 0) // Special case: 0 refers to different initial textures based on the target
+ {
+ switch (type)
+ {
+ default: UNREACHABLE();
+ case TEXTURE_2D: return mTexture2DZero.get();
+ case TEXTURE_CUBE: return mTextureCubeMapZero.get();
+ }
+ }
+
+ return mState.samplerTexture[type][sampler].get();
+}
+
+bool Context::getBooleanv(GLenum pname, GLboolean *params)
+{
+ switch (pname)
+ {
+ case GL_SHADER_COMPILER: *params = GL_TRUE; break;
+ case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break;
+ case GL_DEPTH_WRITEMASK: *params = mState.depthStencil.depthMask; break;
+ case GL_COLOR_WRITEMASK:
+ params[0] = mState.blend.colorMaskRed;
+ params[1] = mState.blend.colorMaskGreen;
+ params[2] = mState.blend.colorMaskBlue;
+ params[3] = mState.blend.colorMaskAlpha;
+ break;
+ case GL_CULL_FACE: *params = mState.rasterizer.cullFace; break;
+ case GL_POLYGON_OFFSET_FILL: *params = mState.rasterizer.polygonOffsetFill; break;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.blend.sampleAlphaToCoverage; break;
+ case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break;
+ case GL_SCISSOR_TEST: *params = mState.scissorTest; break;
+ case GL_STENCIL_TEST: *params = mState.depthStencil.stencilTest; break;
+ case GL_DEPTH_TEST: *params = mState.depthStencil.depthTest; break;
+ case GL_BLEND: *params = mState.blend.blend; break;
+ case GL_DITHER: *params = mState.blend.dither; break;
+ case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool Context::getFloatv(GLenum pname, GLfloat *params)
+{
+ // Please note: DEPTH_CLEAR_VALUE is included in our internal getFloatv implementation
+ // because it is stored as a float, despite the fact that the GL ES 2.0 spec names
+ // GetIntegerv as its native query function. As it would require conversion in any
+ // case, this should make no difference to the calling application.
+ switch (pname)
+ {
+ case GL_LINE_WIDTH: *params = mState.lineWidth; break;
+ case GL_SAMPLE_COVERAGE_VALUE: *params = mState.sampleCoverageValue; break;
+ case GL_DEPTH_CLEAR_VALUE: *params = mState.depthClearValue; break;
+ case GL_POLYGON_OFFSET_FACTOR: *params = mState.rasterizer.polygonOffsetFactor; break;
+ case GL_POLYGON_OFFSET_UNITS: *params = mState.rasterizer.polygonOffsetUnits; break;
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+ params[0] = gl::ALIASED_LINE_WIDTH_RANGE_MIN;
+ params[1] = gl::ALIASED_LINE_WIDTH_RANGE_MAX;
+ break;
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ params[0] = gl::ALIASED_POINT_SIZE_RANGE_MIN;
+ params[1] = getMaximumPointSize();
+ break;
+ case GL_DEPTH_RANGE:
+ params[0] = mState.zNear;
+ params[1] = mState.zFar;
+ break;
+ case GL_COLOR_CLEAR_VALUE:
+ params[0] = mState.colorClearValue.red;
+ params[1] = mState.colorClearValue.green;
+ params[2] = mState.colorClearValue.blue;
+ params[3] = mState.colorClearValue.alpha;
+ break;
+ case GL_BLEND_COLOR:
+ params[0] = mState.blendColor.red;
+ params[1] = mState.blendColor.green;
+ params[2] = mState.blendColor.blue;
+ params[3] = mState.blendColor.alpha;
+ break;
+ case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
+ if (!supportsTextureFilterAnisotropy())
+ {
+ return false;
+ }
+ *params = mMaxTextureAnisotropy;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool Context::getIntegerv(GLenum pname, GLint *params)
+{
+ if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT)
+ {
+ unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT);
+
+ if (colorAttachment >= mRenderer->getMaxRenderTargets())
+ {
+ // return true to stop further operation in the parent call
+ return gl::error(GL_INVALID_OPERATION, true);
+ }
+
+ Framebuffer *framebuffer = getDrawFramebuffer();
+
+ *params = framebuffer->getDrawBufferState(colorAttachment);
+ return true;
+ }
+
+ // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation
+ // because it is stored as a float, despite the fact that the GL ES 2.0 spec names
+ // GetIntegerv as its native query function. As it would require conversion in any
+ // case, this should make no difference to the calling application. You may find it in
+ // Context::getFloatv.
+ switch (pname)
+ {
+ case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break;
+ case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = mRenderer->getMaxVertexUniformVectors(); break;
+ case GL_MAX_VARYING_VECTORS: *params = mRenderer->getMaxVaryingVectors(); break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxCombinedTextureImageUnits(); break;
+ case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mRenderer->getMaxVertexTextureImageUnits(); break;
+ case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break;
+ case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mRenderer->getMaxFragmentUniformVectors(); break;
+ case GL_MAX_RENDERBUFFER_SIZE: *params = getMaximumRenderbufferDimension(); break;
+ case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mRenderer->getMaxRenderTargets(); break;
+ case GL_MAX_DRAW_BUFFERS_EXT: *params = mRenderer->getMaxRenderTargets(); break;
+ case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break;
+ case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break;
+ case GL_ARRAY_BUFFER_BINDING: *params = mState.arrayBuffer.id(); break;
+ case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = mState.elementArrayBuffer.id(); break;
+ //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE
+ case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mState.drawFramebuffer; break;
+ case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mState.readFramebuffer; break;
+ case GL_RENDERBUFFER_BINDING: *params = mState.renderbuffer.id(); break;
+ case GL_CURRENT_PROGRAM: *params = mState.currentProgram; break;
+ case GL_PACK_ALIGNMENT: *params = mState.packAlignment; break;
+ case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mState.packReverseRowOrder; break;
+ case GL_UNPACK_ALIGNMENT: *params = mState.unpackAlignment; break;
+ case GL_GENERATE_MIPMAP_HINT: *params = mState.generateMipmapHint; break;
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; break;
+ case GL_ACTIVE_TEXTURE: *params = (mState.activeSampler + GL_TEXTURE0); break;
+ case GL_STENCIL_FUNC: *params = mState.depthStencil.stencilFunc; break;
+ case GL_STENCIL_REF: *params = mState.stencilRef; break;
+ case GL_STENCIL_VALUE_MASK: *params = mState.depthStencil.stencilMask; break;
+ case GL_STENCIL_BACK_FUNC: *params = mState.depthStencil.stencilBackFunc; break;
+ case GL_STENCIL_BACK_REF: *params = mState.stencilBackRef; break;
+ case GL_STENCIL_BACK_VALUE_MASK: *params = mState.depthStencil.stencilBackMask; break;
+ case GL_STENCIL_FAIL: *params = mState.depthStencil.stencilFail; break;
+ case GL_STENCIL_PASS_DEPTH_FAIL: *params = mState.depthStencil.stencilPassDepthFail; break;
+ case GL_STENCIL_PASS_DEPTH_PASS: *params = mState.depthStencil.stencilPassDepthPass; break;
+ case GL_STENCIL_BACK_FAIL: *params = mState.depthStencil.stencilBackFail; break;
+ case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mState.depthStencil.stencilBackPassDepthFail; break;
+ case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mState.depthStencil.stencilBackPassDepthPass; break;
+ case GL_DEPTH_FUNC: *params = mState.depthStencil.depthFunc; break;
+ case GL_BLEND_SRC_RGB: *params = mState.blend.sourceBlendRGB; break;
+ case GL_BLEND_SRC_ALPHA: *params = mState.blend.sourceBlendAlpha; break;
+ case GL_BLEND_DST_RGB: *params = mState.blend.destBlendRGB; break;
+ case GL_BLEND_DST_ALPHA: *params = mState.blend.destBlendAlpha; break;
+ case GL_BLEND_EQUATION_RGB: *params = mState.blend.blendEquationRGB; break;
+ case GL_BLEND_EQUATION_ALPHA: *params = mState.blend.blendEquationAlpha; break;
+ case GL_STENCIL_WRITEMASK: *params = mState.depthStencil.stencilWritemask; break;
+ case GL_STENCIL_BACK_WRITEMASK: *params = mState.depthStencil.stencilBackWritemask; break;
+ case GL_STENCIL_CLEAR_VALUE: *params = mState.stencilClearValue; break;
+ case GL_SUBPIXEL_BITS: *params = 4; break;
+ case GL_MAX_TEXTURE_SIZE: *params = getMaximumTextureDimension(); break;
+ case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = getMaximumCubeTextureDimension(); break;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ params[0] = mNumCompressedTextureFormats;
+ break;
+ case GL_MAX_SAMPLES_ANGLE:
+ {
+ GLsizei maxSamples = getMaxSupportedSamples();
+ if (maxSamples != 0)
+ {
+ *params = maxSamples;
+ }
+ else
+ {
+ return false;
+ }
+
+ break;
+ }
+ case GL_SAMPLE_BUFFERS:
+ case GL_SAMPLES:
+ {
+ gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ if (framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE)
+ {
+ switch (pname)
+ {
+ case GL_SAMPLE_BUFFERS:
+ if (framebuffer->getSamples() != 0)
+ {
+ *params = 1;
+ }
+ else
+ {
+ *params = 0;
+ }
+ break;
+ case GL_SAMPLES:
+ *params = framebuffer->getSamples();
+ break;
+ }
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE:
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
+ {
+ GLenum format, type;
+ if (getCurrentReadFormatType(&format, &type))
+ {
+ if (pname == GL_IMPLEMENTATION_COLOR_READ_FORMAT)
+ *params = format;
+ else
+ *params = type;
+ }
+ }
+ break;
+ case GL_MAX_VIEWPORT_DIMS:
+ {
+ params[0] = mMaxViewportDimension;
+ params[1] = mMaxViewportDimension;
+ }
+ break;
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ {
+ if (supportsDXT1Textures())
+ {
+ *params++ = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ *params++ = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ }
+ if (supportsDXT3Textures())
+ {
+ *params++ = GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE;
+ }
+ if (supportsDXT5Textures())
+ {
+ *params++ = GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE;
+ }
+ }
+ break;
+ case GL_VIEWPORT:
+ params[0] = mState.viewport.x;
+ params[1] = mState.viewport.y;
+ params[2] = mState.viewport.width;
+ params[3] = mState.viewport.height;
+ break;
+ case GL_SCISSOR_BOX:
+ params[0] = mState.scissor.x;
+ params[1] = mState.scissor.y;
+ params[2] = mState.scissor.width;
+ params[3] = mState.scissor.height;
+ break;
+ case GL_CULL_FACE_MODE: *params = mState.rasterizer.cullMode; break;
+ case GL_FRONT_FACE: *params = mState.rasterizer.frontFace; break;
+ case GL_RED_BITS:
+ case GL_GREEN_BITS:
+ case GL_BLUE_BITS:
+ case GL_ALPHA_BITS:
+ {
+ gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ gl::Renderbuffer *colorbuffer = framebuffer->getFirstColorbuffer();
+
+ if (colorbuffer)
+ {
+ switch (pname)
+ {
+ case GL_RED_BITS: *params = colorbuffer->getRedSize(); break;
+ case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break;
+ case GL_BLUE_BITS: *params = colorbuffer->getBlueSize(); break;
+ case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break;
+ }
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_DEPTH_BITS:
+ {
+ gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ gl::Renderbuffer *depthbuffer = framebuffer->getDepthbuffer();
+
+ if (depthbuffer)
+ {
+ *params = depthbuffer->getDepthSize();
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_STENCIL_BITS:
+ {
+ gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ gl::Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer();
+
+ if (stencilbuffer)
+ {
+ *params = stencilbuffer->getStencilSize();
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_TEXTURE_BINDING_2D:
+ {
+ if (mState.activeSampler > mRenderer->getMaxCombinedTextureImageUnits() - 1)
+ {
+ gl::error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].id();
+ }
+ break;
+ case GL_TEXTURE_BINDING_CUBE_MAP:
+ {
+ if (mState.activeSampler > mRenderer->getMaxCombinedTextureImageUnits() - 1)
+ {
+ gl::error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id();
+ }
+ break;
+ case GL_RESET_NOTIFICATION_STRATEGY_EXT:
+ *params = mResetStrategy;
+ break;
+ case GL_NUM_PROGRAM_BINARY_FORMATS_OES:
+ *params = 1;
+ break;
+ case GL_PROGRAM_BINARY_FORMATS_OES:
+ *params = GL_PROGRAM_BINARY_ANGLE;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams)
+{
+ if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT)
+ {
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ }
+
+ // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation
+ // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due
+ // to the fact that it is stored internally as a float, and so would require conversion
+ // if returned from Context::getIntegerv. Since this conversion is already implemented
+ // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we
+ // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling
+ // application.
+ switch (pname)
+ {
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ {
+ *type = GL_INT;
+ *numParams = mNumCompressedTextureFormats;
+ }
+ break;
+ case GL_SHADER_BINARY_FORMATS:
+ {
+ *type = GL_INT;
+ *numParams = 0;
+ }
+ break;
+ 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:
+ 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:
+ case GL_PROGRAM_BINARY_FORMATS_OES:
+ {
+ *type = GL_INT;
+ *numParams = 1;
+ }
+ break;
+ case GL_MAX_SAMPLES_ANGLE:
+ {
+ if (getMaxSupportedSamples() != 0)
+ {
+ *type = GL_INT;
+ *numParams = 1;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ break;
+ case GL_MAX_VIEWPORT_DIMS:
+ {
+ *type = GL_INT;
+ *numParams = 2;
+ }
+ break;
+ case GL_VIEWPORT:
+ case GL_SCISSOR_BOX:
+ {
+ *type = GL_INT;
+ *numParams = 4;
+ }
+ break;
+ 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;
+ }
+ break;
+ case GL_COLOR_WRITEMASK:
+ {
+ *type = GL_BOOL;
+ *numParams = 4;
+ }
+ break;
+ 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;
+ }
+ break;
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ case GL_DEPTH_RANGE:
+ {
+ *type = GL_FLOAT;
+ *numParams = 2;
+ }
+ break;
+ case GL_COLOR_CLEAR_VALUE:
+ case GL_BLEND_COLOR:
+ {
+ *type = GL_FLOAT;
+ *numParams = 4;
+ }
+ break;
+ case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
+ if (!supportsTextureFilterAnisotropy())
+ {
+ return false;
+ }
+ *type = GL_FLOAT;
+ *numParams = 1;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+// Applies the render target surface, depth stencil surface, viewport rectangle and
+// scissor rectangle to the renderer
+bool Context::applyRenderTarget(GLenum drawMode, bool ignoreViewport)
+{
+ Framebuffer *framebufferObject = getDrawFramebuffer();
+
+ if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
+ }
+
+ mRenderer->applyRenderTarget(framebufferObject);
+
+ if (!mRenderer->setViewport(mState.viewport, mState.zNear, mState.zFar, drawMode, mState.rasterizer.frontFace,
+ ignoreViewport))
+ {
+ return false;
+ }
+
+ mRenderer->setScissorRectangle(mState.scissor, mState.scissorTest);
+
+ return true;
+}
+
+// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device
+void Context::applyState(GLenum drawMode)
+{
+ Framebuffer *framebufferObject = getDrawFramebuffer();
+ int samples = framebufferObject->getSamples();
+
+ mState.rasterizer.pointDrawMode = (drawMode == GL_POINTS);
+ mState.rasterizer.multiSample = (samples != 0);
+ mRenderer->setRasterizerState(mState.rasterizer);
+
+ unsigned int mask = 0;
+ if (mState.sampleCoverage)
+ {
+ if (mState.sampleCoverageValue != 0)
+ {
+
+ float threshold = 0.5f;
+
+ for (int i = 0; i < samples; ++i)
+ {
+ mask <<= 1;
+
+ if ((i + 1) * mState.sampleCoverageValue >= threshold)
+ {
+ threshold += 1.0f;
+ mask |= 1;
+ }
+ }
+ }
+
+ if (mState.sampleCoverageInvert)
+ {
+ mask = ~mask;
+ }
+ }
+ else
+ {
+ mask = 0xFFFFFFFF;
+ }
+ mRenderer->setBlendState(mState.blend, mState.blendColor, mask);
+
+ mRenderer->setDepthStencilState(mState.depthStencil, mState.stencilRef, mState.stencilBackRef,
+ mState.rasterizer.frontFace == GL_CCW);
+}
+
+// Applies the shaders and shader constants to the Direct3D 9 device
+void Context::applyShaders()
+{
+ ProgramBinary *programBinary = getCurrentProgramBinary();
+
+ mRenderer->applyShaders(programBinary);
+
+ programBinary->applyUniforms();
+}
+
+// Applies the textures and sampler states to the Direct3D 9 device
+void Context::applyTextures()
+{
+ applyTextures(SAMPLER_PIXEL);
+
+ if (mSupportsVertexTexture)
+ {
+ applyTextures(SAMPLER_VERTEX);
+ }
+}
+
+// For each Direct3D 9 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).
+void Context::applyTextures(SamplerType type)
+{
+ ProgramBinary *programBinary = getCurrentProgramBinary();
+
+ // Range of Direct3D samplers of given sampler type
+ int samplerCount = (type == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : mRenderer->getMaxVertexTextureImageUnits();
+ int samplerRange = programBinary->getUsedSamplerRange(type);
+
+ for (int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
+ {
+ int textureUnit = programBinary->getSamplerMapping(type, samplerIndex); // OpenGL texture image unit index
+
+ if (textureUnit != -1)
+ {
+ TextureType textureType = programBinary->getSamplerTextureType(type, samplerIndex);
+ Texture *texture = getSamplerTexture(textureUnit, textureType);
+
+ if (texture->isSamplerComplete())
+ {
+ SamplerState samplerState;
+ texture->getSamplerState(&samplerState);
+ mRenderer->setSamplerState(type, samplerIndex, samplerState);
+
+ mRenderer->setTexture(type, samplerIndex, texture);
+
+ texture->resetDirty();
+ }
+ else
+ {
+ mRenderer->setTexture(type, samplerIndex, getIncompleteTexture(textureType));
+ }
+ }
+ else
+ {
+ mRenderer->setTexture(type, samplerIndex, NULL);
+ }
+ }
+
+ for (int samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++)
+ {
+ mRenderer->setTexture(type, samplerIndex, NULL);
+ }
+}
+
+void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLsizei *bufSize, void* pixels)
+{
+ Framebuffer *framebuffer = getReadFramebuffer();
+
+ if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ GLsizei outputPitch = ComputePitch(width, ConvertSizedInternalFormat(format, type), getPackAlignment());
+ // sized query sanity check
+ if (bufSize)
+ {
+ int requiredSize = outputPitch * height;
+ if (requiredSize > *bufSize)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+
+ mRenderer->readPixels(framebuffer, x, y, width, height, format, type, outputPitch, getPackReverseRowOrder(), getPackAlignment(), pixels);
+}
+
+void Context::clear(GLbitfield mask)
+{
+ Framebuffer *framebufferObject = getDrawFramebuffer();
+
+ if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ DWORD flags = 0;
+ GLbitfield finalMask = 0;
+
+ if (mask & GL_COLOR_BUFFER_BIT)
+ {
+ mask &= ~GL_COLOR_BUFFER_BIT;
+
+ if (framebufferObject->hasEnabledColorAttachment())
+ {
+ finalMask |= GL_COLOR_BUFFER_BIT;
+ }
+ }
+
+ if (mask & GL_DEPTH_BUFFER_BIT)
+ {
+ mask &= ~GL_DEPTH_BUFFER_BIT;
+ if (mState.depthStencil.depthMask && framebufferObject->getDepthbufferType() != GL_NONE)
+ {
+ finalMask |= GL_DEPTH_BUFFER_BIT;
+ }
+ }
+
+ if (mask & GL_STENCIL_BUFFER_BIT)
+ {
+ mask &= ~GL_STENCIL_BUFFER_BIT;
+ if (framebufferObject->getStencilbufferType() != GL_NONE)
+ {
+ rx::RenderTarget *depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil();
+ if (!depthStencil)
+ {
+ ERR("Depth stencil pointer unexpectedly null.");
+ return;
+ }
+
+ if (GetStencilSize(depthStencil->getActualFormat()) > 0)
+ {
+ finalMask |= GL_STENCIL_BUFFER_BIT;
+ }
+ }
+ }
+
+ if (mask != 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (!applyRenderTarget(GL_TRIANGLES, true)) // Clips the clear to the scissor rectangle but not the viewport
+ {
+ return;
+ }
+
+ ClearParameters clearParams;
+ clearParams.mask = finalMask;
+ clearParams.colorClearValue = mState.colorClearValue;
+ clearParams.colorMaskRed = mState.blend.colorMaskRed;
+ clearParams.colorMaskGreen = mState.blend.colorMaskGreen;
+ clearParams.colorMaskBlue = mState.blend.colorMaskBlue;
+ clearParams.colorMaskAlpha = mState.blend.colorMaskAlpha;
+ clearParams.depthClearValue = mState.depthClearValue;
+ clearParams.stencilClearValue = mState.stencilClearValue;
+ clearParams.stencilWriteMask = mState.depthStencil.stencilWritemask;
+
+ mRenderer->clear(clearParams, framebufferObject);
+}
+
+void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances)
+{
+ if (!mState.currentProgram)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!mRenderer->applyPrimitiveType(mode, count))
+ {
+ return;
+ }
+
+ if (!applyRenderTarget(mode, false))
+ {
+ return;
+ }
+
+ applyState(mode);
+
+ ProgramBinary *programBinary = getCurrentProgramBinary();
+
+ GLenum err = mRenderer->applyVertexBuffer(programBinary, mState.vertexAttribute, first, count, instances);
+ if (err != GL_NO_ERROR)
+ {
+ return gl::error(err);
+ }
+
+ applyShaders();
+ applyTextures();
+
+ if (!programBinary->validateSamplers(NULL))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!skipDraw(mode))
+ {
+ mRenderer->drawArrays(mode, count, instances);
+ }
+}
+
+void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances)
+{
+ if (!mState.currentProgram)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!indices && !mState.elementArrayBuffer)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!mRenderer->applyPrimitiveType(mode, count))
+ {
+ return;
+ }
+
+ if (!applyRenderTarget(mode, false))
+ {
+ return;
+ }
+
+ applyState(mode);
+
+ rx::TranslatedIndexData indexInfo;
+ GLenum err = mRenderer->applyIndexBuffer(indices, mState.elementArrayBuffer.get(), count, mode, type, &indexInfo);
+ if (err != GL_NO_ERROR)
+ {
+ return gl::error(err);
+ }
+
+ ProgramBinary *programBinary = getCurrentProgramBinary();
+
+ GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
+ err = mRenderer->applyVertexBuffer(programBinary, mState.vertexAttribute, indexInfo.minIndex, vertexCount, instances);
+ if (err != GL_NO_ERROR)
+ {
+ return gl::error(err);
+ }
+
+ applyShaders();
+ applyTextures();
+
+ if (!programBinary->validateSamplers(NULL))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!skipDraw(mode))
+ {
+ mRenderer->drawElements(mode, count, type, indices, mState.elementArrayBuffer.get(), indexInfo, instances);
+ }
+}
+
+// Implements glFlush when block is false, glFinish when block is true
+void Context::sync(bool block)
+{
+ mRenderer->sync(block);
+}
+
+void Context::recordInvalidEnum()
+{
+ mInvalidEnum = true;
+}
+
+void Context::recordInvalidValue()
+{
+ mInvalidValue = true;
+}
+
+void Context::recordInvalidOperation()
+{
+ mInvalidOperation = true;
+}
+
+void Context::recordOutOfMemory()
+{
+ mOutOfMemory = true;
+}
+
+void Context::recordInvalidFramebufferOperation()
+{
+ mInvalidFramebufferOperation = true;
+}
+
+// Get one of the recorded errors and clear its flag, if any.
+// [OpenGL ES 2.0.24] section 2.5 page 13.
+GLenum Context::getError()
+{
+ if (mInvalidEnum)
+ {
+ mInvalidEnum = false;
+
+ return GL_INVALID_ENUM;
+ }
+
+ if (mInvalidValue)
+ {
+ mInvalidValue = false;
+
+ return GL_INVALID_VALUE;
+ }
+
+ if (mInvalidOperation)
+ {
+ mInvalidOperation = false;
+
+ return GL_INVALID_OPERATION;
+ }
+
+ if (mOutOfMemory)
+ {
+ mOutOfMemory = false;
+
+ return GL_OUT_OF_MEMORY;
+ }
+
+ if (mInvalidFramebufferOperation)
+ {
+ mInvalidFramebufferOperation = false;
+
+ return GL_INVALID_FRAMEBUFFER_OPERATION;
+ }
+
+ return GL_NO_ERROR;
+}
+
+GLenum Context::getResetStatus()
+{
+ if (mResetStatus == GL_NO_ERROR && !mContextLost)
+ {
+ // mResetStatus will be set by the markContextLost callback
+ // in the case a notification is sent
+ mRenderer->testDeviceLost(true);
+ }
+
+ GLenum status = mResetStatus;
+
+ if (mResetStatus != GL_NO_ERROR)
+ {
+ ASSERT(mContextLost);
+
+ if (mRenderer->testDeviceResettable())
+ {
+ mResetStatus = GL_NO_ERROR;
+ }
+ }
+
+ return status;
+}
+
+bool Context::isResetNotificationEnabled()
+{
+ return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT);
+}
+
+int Context::getMajorShaderModel() const
+{
+ return mMajorShaderModel;
+}
+
+float Context::getMaximumPointSize() const
+{
+ return mMaximumPointSize;
+}
+
+unsigned int Context::getMaximumCombinedTextureImageUnits() const
+{
+ return mRenderer->getMaxCombinedTextureImageUnits();
+}
+
+int Context::getMaxSupportedSamples() const
+{
+ return mRenderer->getMaxSupportedSamples();
+}
+
+unsigned int Context::getMaximumRenderTargets() const
+{
+ return mRenderer->getMaxRenderTargets();
+}
+
+bool Context::supportsEventQueries() const
+{
+ return mSupportsEventQueries;
+}
+
+bool Context::supportsOcclusionQueries() const
+{
+ return mSupportsOcclusionQueries;
+}
+
+bool Context::supportsBGRATextures() const
+{
+ return mSupportsBGRATextures;
+}
+
+bool Context::supportsDXT1Textures() const
+{
+ return mSupportsDXT1Textures;
+}
+
+bool Context::supportsDXT3Textures() const
+{
+ return mSupportsDXT3Textures;
+}
+
+bool Context::supportsDXT5Textures() const
+{
+ return mSupportsDXT5Textures;
+}
+
+bool Context::supportsFloat32Textures() const
+{
+ return mSupportsFloat32Textures;
+}
+
+bool Context::supportsFloat32LinearFilter() const
+{
+ return mSupportsFloat32LinearFilter;
+}
+
+bool Context::supportsFloat32RenderableTextures() const
+{
+ return mSupportsFloat32RenderableTextures;
+}
+
+bool Context::supportsFloat16Textures() const
+{
+ return mSupportsFloat16Textures;
+}
+
+bool Context::supportsFloat16LinearFilter() const
+{
+ return mSupportsFloat16LinearFilter;
+}
+
+bool Context::supportsFloat16RenderableTextures() const
+{
+ return mSupportsFloat16RenderableTextures;
+}
+
+int Context::getMaximumRenderbufferDimension() const
+{
+ return mMaxRenderbufferDimension;
+}
+
+int Context::getMaximumTextureDimension() const
+{
+ return mMaxTextureDimension;
+}
+
+int Context::getMaximumCubeTextureDimension() const
+{
+ return mMaxCubeTextureDimension;
+}
+
+int Context::getMaximumTextureLevel() const
+{
+ return mMaxTextureLevel;
+}
+
+bool Context::supportsLuminanceTextures() const
+{
+ return mSupportsLuminanceTextures;
+}
+
+bool Context::supportsLuminanceAlphaTextures() const
+{
+ return mSupportsLuminanceAlphaTextures;
+}
+
+bool Context::supportsDepthTextures() const
+{
+ return mSupportsDepthTextures;
+}
+
+bool Context::supports32bitIndices() const
+{
+ return mSupports32bitIndices;
+}
+
+bool Context::supportsNonPower2Texture() const
+{
+ return mSupportsNonPower2Texture;
+}
+
+bool Context::supportsInstancing() const
+{
+ return mSupportsInstancing;
+}
+
+bool Context::supportsTextureFilterAnisotropy() const
+{
+ return mSupportsTextureFilterAnisotropy;
+}
+
+float Context::getTextureMaxAnisotropy() const
+{
+ return mMaxTextureAnisotropy;
+}
+
+bool Context::getCurrentReadFormatType(GLenum *format, GLenum *type)
+{
+ Framebuffer *framebuffer = getReadFramebuffer();
+ if (!framebuffer || framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ Renderbuffer *renderbuffer = framebuffer->getReadColorbuffer();
+ if (!renderbuffer)
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ *format = gl::ExtractFormat(renderbuffer->getActualFormat());
+ *type = gl::ExtractType(renderbuffer->getActualFormat());
+
+ return true;
+}
+
+void Context::detachBuffer(GLuint buffer)
+{
+ // [OpenGL ES 2.0.24] section 2.9 page 22:
+ // If a buffer object is deleted while it is bound, all bindings to that object in the current context
+ // (i.e. in the thread that called Delete-Buffers) are reset to zero.
+
+ if (mState.arrayBuffer.id() == buffer)
+ {
+ mState.arrayBuffer.set(NULL);
+ }
+
+ if (mState.elementArrayBuffer.id() == buffer)
+ {
+ mState.elementArrayBuffer.set(NULL);
+ }
+
+ for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
+ {
+ if (mState.vertexAttribute[attribute].mBoundBuffer.id() == buffer)
+ {
+ mState.vertexAttribute[attribute].mBoundBuffer.set(NULL);
+ }
+ }
+}
+
+void Context::detachTexture(GLuint texture)
+{
+ // [OpenGL ES 2.0.24] section 3.8 page 84:
+ // If a texture object is deleted, it is as if all texture units which are bound to that texture object are
+ // rebound to texture object zero
+
+ for (int type = 0; type < TEXTURE_TYPE_COUNT; type++)
+ {
+ for (int sampler = 0; sampler < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; sampler++)
+ {
+ if (mState.samplerTexture[type][sampler].id() == texture)
+ {
+ mState.samplerTexture[type][sampler].set(NULL);
+ }
+ }
+ }
+
+ // [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 FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this
+ // image was attached in the currently bound framebuffer.
+
+ Framebuffer *readFramebuffer = getReadFramebuffer();
+ Framebuffer *drawFramebuffer = getDrawFramebuffer();
+
+ if (readFramebuffer)
+ {
+ readFramebuffer->detachTexture(texture);
+ }
+
+ if (drawFramebuffer && drawFramebuffer != readFramebuffer)
+ {
+ drawFramebuffer->detachTexture(texture);
+ }
+}
+
+void Context::detachFramebuffer(GLuint framebuffer)
+{
+ // [OpenGL ES 2.0.24] section 4.4 page 107:
+ // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though
+ // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero.
+
+ if (mState.readFramebuffer == framebuffer)
+ {
+ bindReadFramebuffer(0);
+ }
+
+ if (mState.drawFramebuffer == framebuffer)
+ {
+ bindDrawFramebuffer(0);
+ }
+}
+
+void Context::detachRenderbuffer(GLuint renderbuffer)
+{
+ // [OpenGL ES 2.0.24] section 4.4 page 109:
+ // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer
+ // had been executed with the target RENDERBUFFER and name of zero.
+
+ if (mState.renderbuffer.id() == renderbuffer)
+ {
+ bindRenderbuffer(0);
+ }
+
+ // [OpenGL ES 2.0.24] section 4.4 page 111:
+ // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer,
+ // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment
+ // point to which this image was attached in the currently bound framebuffer.
+
+ Framebuffer *readFramebuffer = getReadFramebuffer();
+ Framebuffer *drawFramebuffer = getDrawFramebuffer();
+
+ if (readFramebuffer)
+ {
+ readFramebuffer->detachRenderbuffer(renderbuffer);
+ }
+
+ if (drawFramebuffer && drawFramebuffer != readFramebuffer)
+ {
+ drawFramebuffer->detachRenderbuffer(renderbuffer);
+ }
+}
+
+Texture *Context::getIncompleteTexture(TextureType type)
+{
+ Texture *t = mIncompleteTextures[type].get();
+
+ if (t == NULL)
+ {
+ static const GLubyte color[] = { 0, 0, 0, 255 };
+
+ switch (type)
+ {
+ default:
+ UNREACHABLE();
+ // default falls through to TEXTURE_2D
+
+ case TEXTURE_2D:
+ {
+ Texture2D *incomplete2d = new Texture2D(mRenderer, Texture::INCOMPLETE_TEXTURE_ID);
+ incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ t = incomplete2d;
+ }
+ break;
+
+ case TEXTURE_CUBE:
+ {
+ TextureCubeMap *incompleteCube = new TextureCubeMap(mRenderer, Texture::INCOMPLETE_TEXTURE_ID);
+
+ incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+
+ t = incompleteCube;
+ }
+ break;
+ }
+
+ mIncompleteTextures[type].set(t);
+ }
+
+ return t;
+}
+
+bool Context::skipDraw(GLenum drawMode)
+{
+ if (drawMode == GL_POINTS)
+ {
+ // ProgramBinary assumes non-point rendering if gl_PointSize isn't written,
+ // which affects varying interpolation. Since the value of gl_PointSize is
+ // undefined when not written, just skip drawing to avoid unexpected results.
+ if (!getCurrentProgramBinary()->usesPointSize())
+ {
+ // This is stictly speaking not an error, but developers should be
+ // notified of risking undefined behavior.
+ ERR("Point rendering without writing to gl_PointSize.");
+
+ return true;
+ }
+ }
+ else if (IsTriangleMode(drawMode))
+ {
+ if (mState.rasterizer.cullFace && mState.rasterizer.cullMode == GL_FRONT_AND_BACK)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Context::setVertexAttrib(GLuint index, const GLfloat *values)
+{
+ ASSERT(index < gl::MAX_VERTEX_ATTRIBS);
+
+ mState.vertexAttribute[index].mCurrentValue[0] = values[0];
+ mState.vertexAttribute[index].mCurrentValue[1] = values[1];
+ mState.vertexAttribute[index].mCurrentValue[2] = values[2];
+ mState.vertexAttribute[index].mCurrentValue[3] = values[3];
+}
+
+void Context::setVertexAttribDivisor(GLuint index, GLuint divisor)
+{
+ ASSERT(index < gl::MAX_VERTEX_ATTRIBS);
+
+ mState.vertexAttribute[index].mDivisor = divisor;
+}
+
+// keep list sorted in following order
+// OES extensions
+// EXT extensions
+// Vendor extensions
+void Context::initExtensionString()
+{
+ std::string extensionString = "";
+
+ // OES extensions
+ if (supports32bitIndices())
+ {
+ extensionString += "GL_OES_element_index_uint ";
+ }
+
+ extensionString += "GL_OES_packed_depth_stencil ";
+ extensionString += "GL_OES_get_program_binary ";
+ extensionString += "GL_OES_rgb8_rgba8 ";
+ if (mRenderer->getDerivativeInstructionSupport())
+ {
+ extensionString += "GL_OES_standard_derivatives ";
+ }
+
+ if (supportsFloat16Textures())
+ {
+ extensionString += "GL_OES_texture_half_float ";
+ }
+ if (supportsFloat16LinearFilter())
+ {
+ extensionString += "GL_OES_texture_half_float_linear ";
+ }
+ if (supportsFloat32Textures())
+ {
+ extensionString += "GL_OES_texture_float ";
+ }
+ if (supportsFloat32LinearFilter())
+ {
+ extensionString += "GL_OES_texture_float_linear ";
+ }
+
+ if (supportsNonPower2Texture())
+ {
+ extensionString += "GL_OES_texture_npot ";
+ }
+
+ // Multi-vendor (EXT) extensions
+ if (supportsOcclusionQueries())
+ {
+ extensionString += "GL_EXT_occlusion_query_boolean ";
+ }
+
+ extensionString += "GL_EXT_read_format_bgra ";
+ extensionString += "GL_EXT_robustness ";
+
+ if (supportsDXT1Textures())
+ {
+ extensionString += "GL_EXT_texture_compression_dxt1 ";
+ }
+
+ if (supportsTextureFilterAnisotropy())
+ {
+ extensionString += "GL_EXT_texture_filter_anisotropic ";
+ }
+
+ if (supportsBGRATextures())
+ {
+ extensionString += "GL_EXT_texture_format_BGRA8888 ";
+ }
+
+ if (mRenderer->getMaxRenderTargets() > 1)
+ {
+ extensionString += "GL_EXT_draw_buffers ";
+ }
+
+ extensionString += "GL_EXT_texture_storage ";
+ extensionString += "GL_EXT_frag_depth ";
+
+ // ANGLE-specific extensions
+ if (supportsDepthTextures())
+ {
+ extensionString += "GL_ANGLE_depth_texture ";
+ }
+
+ extensionString += "GL_ANGLE_framebuffer_blit ";
+ if (getMaxSupportedSamples() != 0)
+ {
+ extensionString += "GL_ANGLE_framebuffer_multisample ";
+ }
+
+ if (supportsInstancing())
+ {
+ extensionString += "GL_ANGLE_instanced_arrays ";
+ }
+
+ extensionString += "GL_ANGLE_pack_reverse_row_order ";
+
+ if (supportsDXT3Textures())
+ {
+ extensionString += "GL_ANGLE_texture_compression_dxt3 ";
+ }
+ if (supportsDXT5Textures())
+ {
+ extensionString += "GL_ANGLE_texture_compression_dxt5 ";
+ }
+
+ extensionString += "GL_ANGLE_texture_usage ";
+ extensionString += "GL_ANGLE_translated_shader_source ";
+
+ // Other vendor-specific extensions
+ if (supportsEventQueries())
+ {
+ extensionString += "GL_NV_fence ";
+ }
+
+ std::string::size_type end = extensionString.find_last_not_of(' ');
+ if (end != std::string::npos)
+ {
+ extensionString.resize(end+1);
+ }
+
+ mExtensionString = makeStaticString(extensionString);
+}
+
+const char *Context::getExtensionString() const
+{
+ return mExtensionString;
+}
+
+void Context::initRendererString()
+{
+ std::ostringstream rendererString;
+ rendererString << "ANGLE (";
+ rendererString << mRenderer->getRendererDescription();
+ rendererString << ")";
+
+ mRendererString = makeStaticString(rendererString.str());
+}
+
+const char *Context::getRendererString() const
+{
+ return mRendererString;
+}
+
+void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask)
+{
+ Framebuffer *readFramebuffer = getReadFramebuffer();
+ Framebuffer *drawFramebuffer = getDrawFramebuffer();
+
+ if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
+ !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if (drawFramebuffer->getSamples() != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ Renderbuffer *readColorBuffer = readFramebuffer->getReadColorbuffer();
+ Renderbuffer *drawColorBuffer = drawFramebuffer->getFirstColorbuffer();
+
+ if (drawColorBuffer == NULL)
+ {
+ ERR("Draw buffers formats don't match, which is not supported in this implementation of BlitFramebufferANGLE");
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ int readBufferWidth = readColorBuffer->getWidth();
+ int readBufferHeight = readColorBuffer->getHeight();
+ int drawBufferWidth = drawColorBuffer->getWidth();
+ int drawBufferHeight = drawColorBuffer->getHeight();
+
+ Rectangle sourceRect;
+ Rectangle destRect;
+
+ if (srcX0 < srcX1)
+ {
+ sourceRect.x = srcX0;
+ destRect.x = dstX0;
+ sourceRect.width = srcX1 - srcX0;
+ destRect.width = dstX1 - dstX0;
+ }
+ else
+ {
+ sourceRect.x = srcX1;
+ destRect.x = dstX1;
+ sourceRect.width = srcX0 - srcX1;
+ destRect.width = dstX0 - dstX1;
+ }
+
+ if (srcY0 < srcY1)
+ {
+ sourceRect.height = srcY1 - srcY0;
+ destRect.height = dstY1 - dstY0;
+ sourceRect.y = srcY0;
+ destRect.y = dstY0;
+ }
+ else
+ {
+ sourceRect.height = srcY0 - srcY1;
+ destRect.height = dstY0 - srcY1;
+ sourceRect.y = srcY1;
+ destRect.y = dstY1;
+ }
+
+ Rectangle sourceScissoredRect = sourceRect;
+ Rectangle destScissoredRect = destRect;
+
+ if (mState.scissorTest)
+ {
+ // Only write to parts of the destination framebuffer which pass the scissor test.
+ if (destRect.x < mState.scissor.x)
+ {
+ int xDiff = mState.scissor.x - destRect.x;
+ destScissoredRect.x = mState.scissor.x;
+ destScissoredRect.width -= xDiff;
+ sourceScissoredRect.x += xDiff;
+ sourceScissoredRect.width -= xDiff;
+
+ }
+
+ if (destRect.x + destRect.width > mState.scissor.x + mState.scissor.width)
+ {
+ int xDiff = (destRect.x + destRect.width) - (mState.scissor.x + mState.scissor.width);
+ destScissoredRect.width -= xDiff;
+ sourceScissoredRect.width -= xDiff;
+ }
+
+ if (destRect.y < mState.scissor.y)
+ {
+ int yDiff = mState.scissor.y - destRect.y;
+ destScissoredRect.y = mState.scissor.y;
+ destScissoredRect.height -= yDiff;
+ sourceScissoredRect.y += yDiff;
+ sourceScissoredRect.height -= yDiff;
+ }
+
+ if (destRect.y + destRect.height > mState.scissor.y + mState.scissor.height)
+ {
+ int yDiff = (destRect.y + destRect.height) - (mState.scissor.y + mState.scissor.height);
+ destScissoredRect.height -= yDiff;
+ sourceScissoredRect.height -= yDiff;
+ }
+ }
+
+ bool blitRenderTarget = false;
+ bool blitDepthStencil = false;
+
+ Rectangle sourceTrimmedRect = sourceScissoredRect;
+ Rectangle destTrimmedRect = destScissoredRect;
+
+ // The source & destination rectangles also may need to be trimmed if they fall out of the bounds of
+ // the actual draw and read surfaces.
+ if (sourceTrimmedRect.x < 0)
+ {
+ int xDiff = 0 - sourceTrimmedRect.x;
+ sourceTrimmedRect.x = 0;
+ sourceTrimmedRect.width -= xDiff;
+ destTrimmedRect.x += xDiff;
+ destTrimmedRect.width -= xDiff;
+ }
+
+ if (sourceTrimmedRect.x + sourceTrimmedRect.width > readBufferWidth)
+ {
+ int xDiff = (sourceTrimmedRect.x + sourceTrimmedRect.width) - readBufferWidth;
+ sourceTrimmedRect.width -= xDiff;
+ destTrimmedRect.width -= xDiff;
+ }
+
+ if (sourceTrimmedRect.y < 0)
+ {
+ int yDiff = 0 - sourceTrimmedRect.y;
+ sourceTrimmedRect.y = 0;
+ sourceTrimmedRect.height -= yDiff;
+ destTrimmedRect.y += yDiff;
+ destTrimmedRect.height -= yDiff;
+ }
+
+ if (sourceTrimmedRect.y + sourceTrimmedRect.height > readBufferHeight)
+ {
+ int yDiff = (sourceTrimmedRect.y + sourceTrimmedRect.height) - readBufferHeight;
+ sourceTrimmedRect.height -= yDiff;
+ destTrimmedRect.height -= yDiff;
+ }
+
+ if (destTrimmedRect.x < 0)
+ {
+ int xDiff = 0 - destTrimmedRect.x;
+ destTrimmedRect.x = 0;
+ destTrimmedRect.width -= xDiff;
+ sourceTrimmedRect.x += xDiff;
+ sourceTrimmedRect.width -= xDiff;
+ }
+
+ if (destTrimmedRect.x + destTrimmedRect.width > drawBufferWidth)
+ {
+ int xDiff = (destTrimmedRect.x + destTrimmedRect.width) - drawBufferWidth;
+ destTrimmedRect.width -= xDiff;
+ sourceTrimmedRect.width -= xDiff;
+ }
+
+ if (destTrimmedRect.y < 0)
+ {
+ int yDiff = 0 - destTrimmedRect.y;
+ destTrimmedRect.y = 0;
+ destTrimmedRect.height -= yDiff;
+ sourceTrimmedRect.y += yDiff;
+ sourceTrimmedRect.height -= yDiff;
+ }
+
+ if (destTrimmedRect.y + destTrimmedRect.height > drawBufferHeight)
+ {
+ int yDiff = (destTrimmedRect.y + destTrimmedRect.height) - drawBufferHeight;
+ destTrimmedRect.height -= yDiff;
+ sourceTrimmedRect.height -= yDiff;
+ }
+
+ bool partialBufferCopy = false;
+ if (sourceTrimmedRect.height < readBufferHeight ||
+ sourceTrimmedRect.width < readBufferWidth ||
+ destTrimmedRect.height < drawBufferHeight ||
+ destTrimmedRect.width < drawBufferWidth ||
+ sourceTrimmedRect.y != 0 || destTrimmedRect.y != 0 || sourceTrimmedRect.x != 0 || destTrimmedRect.x != 0)
+ {
+ partialBufferCopy = true;
+ }
+
+ if (mask & GL_COLOR_BUFFER_BIT)
+ {
+ const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
+ const bool validReadType = (readColorbufferType == GL_TEXTURE_2D) || (readColorbufferType == GL_RENDERBUFFER);
+ bool validDrawType = true;
+ bool validDrawFormat = true;
+
+ for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (drawFramebuffer->isEnabledColorAttachment(colorAttachment))
+ {
+ if (drawFramebuffer->getColorbufferType(colorAttachment) != GL_TEXTURE_2D &&
+ drawFramebuffer->getColorbufferType(colorAttachment) != GL_RENDERBUFFER)
+ {
+ validDrawType = false;
+ }
+
+ if (drawFramebuffer->getColorbuffer(colorAttachment)->getActualFormat() != readColorBuffer->getActualFormat())
+ {
+ validDrawFormat = false;
+ }
+ }
+ }
+
+ if (!validReadType || !validDrawType || !validDrawFormat)
+ {
+ ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation");
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (partialBufferCopy && readFramebuffer->getSamples() != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ blitRenderTarget = true;
+
+ }
+
+ if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
+ {
+ Renderbuffer *readDSBuffer = NULL;
+ Renderbuffer *drawDSBuffer = NULL;
+
+ // We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have
+ // both a depth and stencil buffer, it will be the same buffer.
+
+ if (mask & GL_DEPTH_BUFFER_BIT)
+ {
+ if (readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer())
+ {
+ if (readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() ||
+ readFramebuffer->getDepthbuffer()->getActualFormat() != drawFramebuffer->getDepthbuffer()->getActualFormat())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ blitDepthStencil = true;
+ readDSBuffer = readFramebuffer->getDepthbuffer();
+ drawDSBuffer = drawFramebuffer->getDepthbuffer();
+ }
+ }
+
+ if (mask & GL_STENCIL_BUFFER_BIT)
+ {
+ if (readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer())
+ {
+ if (readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() ||
+ readFramebuffer->getStencilbuffer()->getActualFormat() != drawFramebuffer->getStencilbuffer()->getActualFormat())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ blitDepthStencil = true;
+ readDSBuffer = readFramebuffer->getStencilbuffer();
+ drawDSBuffer = drawFramebuffer->getStencilbuffer();
+ }
+ }
+
+ if (partialBufferCopy)
+ {
+ ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
+ return gl::error(GL_INVALID_OPERATION); // only whole-buffer copies are permitted
+ }
+
+ if ((drawDSBuffer && drawDSBuffer->getSamples() != 0) ||
+ (readDSBuffer && readDSBuffer->getSamples() != 0))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+
+ if (blitRenderTarget || blitDepthStencil)
+ {
+ mRenderer->blitRect(readFramebuffer, sourceTrimmedRect, drawFramebuffer, destTrimmedRect, blitRenderTarget, blitDepthStencil);
+ }
+}
+
+}
+
+extern "C"
+{
+gl::Context *glCreateContext(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess)
+{
+ return new gl::Context(shareContext, renderer, notifyResets, robustAccess);
+}
+
+void glDestroyContext(gl::Context *context)
+{
+ delete context;
+
+ if (context == gl::getContext())
+ {
+ gl::makeCurrent(NULL, NULL, NULL);
+ }
+}
+
+void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface)
+{
+ gl::makeCurrent(context, display, surface);
+}
+
+gl::Context *glGetCurrentContext()
+{
+ return gl::getContext();
+}
+
+}
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
new file mode 100644
index 00000000..9c222be2
--- /dev/null
+++ b/src/libGLESv2/Context.h
@@ -0,0 +1,505 @@
+//
+// 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.
+//
+
+// Context.h: Defines the gl::Context class, managing all GL state and performing
+// rendering operations. It is the GLES2 specific implementation of EGLContext.
+
+#ifndef LIBGLESV2_CONTEXT_H_
+#define LIBGLESV2_CONTEXT_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#define EGLAPI
+#include <EGL/egl.h>
+
+#include <string>
+#include <map>
+#ifdef _MSC_VER
+#include <hash_map>
+#else
+#include <unordered_map>
+#endif
+
+#include "common/angleutils.h"
+#include "common/RefCountObject.h"
+#include "libGLESv2/HandleAllocator.h"
+#include "libGLESv2/angletypes.h"
+#include "libGLESv2/Constants.h"
+
+namespace rx
+{
+class Renderer;
+}
+
+namespace egl
+{
+class Display;
+class Surface;
+}
+
+namespace gl
+{
+class Shader;
+class Program;
+class ProgramBinary;
+class Texture;
+class Texture2D;
+class TextureCubeMap;
+class Framebuffer;
+class Renderbuffer;
+class RenderbufferStorage;
+class Colorbuffer;
+class Depthbuffer;
+class Stencilbuffer;
+class DepthStencilbuffer;
+class Fence;
+class Query;
+class ResourceManager;
+class Buffer;
+
+enum QueryType
+{
+ QUERY_ANY_SAMPLES_PASSED,
+ QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE,
+
+ QUERY_TYPE_COUNT
+};
+
+// Helper structure describing a single vertex attribute
+class VertexAttribute
+{
+ public:
+ VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false), mDivisor(0)
+ {
+ mCurrentValue[0] = 0.0f;
+ mCurrentValue[1] = 0.0f;
+ mCurrentValue[2] = 0.0f;
+ mCurrentValue[3] = 1.0f;
+ }
+
+ int typeSize() const
+ {
+ switch (mType)
+ {
+ case GL_BYTE: return mSize * sizeof(GLbyte);
+ case GL_UNSIGNED_BYTE: return mSize * sizeof(GLubyte);
+ case GL_SHORT: return mSize * sizeof(GLshort);
+ case GL_UNSIGNED_SHORT: return mSize * sizeof(GLushort);
+ case GL_FIXED: return mSize * sizeof(GLfixed);
+ case GL_FLOAT: return mSize * sizeof(GLfloat);
+ default: UNREACHABLE(); return mSize * sizeof(GLfloat);
+ }
+ }
+
+ GLsizei stride() const
+ {
+ return mStride ? mStride : typeSize();
+ }
+
+ // From glVertexAttribPointer
+ GLenum mType;
+ GLint mSize;
+ bool mNormalized;
+ GLsizei mStride; // 0 means natural stride
+
+ union
+ {
+ const void *mPointer;
+ intptr_t mOffset;
+ };
+
+ BindingPointer<Buffer> mBoundBuffer; // Captured when glVertexAttribPointer is called.
+
+ bool mArrayEnabled; // From glEnable/DisableVertexAttribArray
+ float mCurrentValue[4]; // From glVertexAttrib
+ unsigned int mDivisor;
+};
+
+// Helper structure to store all raw state
+struct State
+{
+ Color colorClearValue;
+ GLclampf depthClearValue;
+ int stencilClearValue;
+
+ RasterizerState rasterizer;
+ bool scissorTest;
+ Rectangle scissor;
+
+ BlendState blend;
+ Color blendColor;
+ bool sampleCoverage;
+ GLclampf sampleCoverageValue;
+ bool sampleCoverageInvert;
+
+ DepthStencilState depthStencil;
+ GLint stencilRef;
+ GLint stencilBackRef;
+
+ GLfloat lineWidth;
+
+ GLenum generateMipmapHint;
+ GLenum fragmentShaderDerivativeHint;
+
+ Rectangle viewport;
+ float zNear;
+ float zFar;
+
+ unsigned int activeSampler; // Active texture unit selector - GL_TEXTURE0
+ BindingPointer<Buffer> arrayBuffer;
+ BindingPointer<Buffer> elementArrayBuffer;
+ GLuint readFramebuffer;
+ GLuint drawFramebuffer;
+ BindingPointer<Renderbuffer> renderbuffer;
+ GLuint currentProgram;
+
+ VertexAttribute vertexAttribute[MAX_VERTEX_ATTRIBS];
+ BindingPointer<Texture> samplerTexture[TEXTURE_TYPE_COUNT][IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+ BindingPointer<Query> activeQuery[QUERY_TYPE_COUNT];
+
+ GLint unpackAlignment;
+ GLint packAlignment;
+ bool packReverseRowOrder;
+};
+
+class Context
+{
+ public:
+ Context(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess);
+
+ ~Context();
+
+ void makeCurrent(egl::Surface *surface);
+
+ virtual void markContextLost();
+ bool isContextLost();
+
+ // State manipulation
+ void setClearColor(float red, float green, float blue, float alpha);
+
+ void setClearDepth(float depth);
+
+ void setClearStencil(int stencil);
+
+ void setCullFace(bool enabled);
+ bool isCullFaceEnabled() const;
+
+ void setCullMode(GLenum mode);
+
+ void setFrontFace(GLenum front);
+
+ void setDepthTest(bool enabled);
+ bool isDepthTestEnabled() const;
+
+ void setDepthFunc(GLenum depthFunc);
+
+ void setDepthRange(float zNear, float zFar);
+
+ void setBlend(bool enabled);
+ bool isBlendEnabled() const;
+
+ void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha);
+ void setBlendColor(float red, float green, float blue, float alpha);
+ void setBlendEquation(GLenum rgbEquation, GLenum alphaEquation);
+
+ void setStencilTest(bool enabled);
+ bool isStencilTestEnabled() const;
+
+ void setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask);
+ void setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask);
+ void setStencilWritemask(GLuint stencilWritemask);
+ void setStencilBackWritemask(GLuint stencilBackWritemask);
+ void setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass);
+ void setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass);
+
+ void setPolygonOffsetFill(bool enabled);
+ bool isPolygonOffsetFillEnabled() const;
+
+ void setPolygonOffsetParams(GLfloat factor, GLfloat units);
+
+ void setSampleAlphaToCoverage(bool enabled);
+ bool isSampleAlphaToCoverageEnabled() const;
+
+ void setSampleCoverage(bool enabled);
+ bool isSampleCoverageEnabled() const;
+
+ void setSampleCoverageParams(GLclampf value, bool invert);
+
+ void setScissorTest(bool enabled);
+ bool isScissorTestEnabled() const;
+
+ void setDither(bool enabled);
+ bool isDitherEnabled() const;
+
+ void setLineWidth(GLfloat width);
+
+ void setGenerateMipmapHint(GLenum hint);
+ void setFragmentShaderDerivativeHint(GLenum hint);
+
+ void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height);
+
+ void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height);
+
+ void setColorMask(bool red, bool green, bool blue, bool alpha);
+ void setDepthMask(bool mask);
+
+ void setActiveSampler(unsigned int active);
+
+ GLuint getReadFramebufferHandle() const;
+ GLuint getDrawFramebufferHandle() const;
+ GLuint getRenderbufferHandle() const;
+
+ GLuint getArrayBufferHandle() const;
+
+ GLuint getActiveQuery(GLenum target) const;
+
+ void setEnableVertexAttribArray(unsigned int attribNum, bool enabled);
+ const VertexAttribute &getVertexAttribState(unsigned int attribNum);
+ void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
+ bool normalized, GLsizei stride, const void *pointer);
+ const void *getVertexAttribPointer(unsigned int attribNum) const;
+
+ void setUnpackAlignment(GLint alignment);
+ GLint getUnpackAlignment() const;
+
+ void setPackAlignment(GLint alignment);
+ GLint getPackAlignment() const;
+
+ void setPackReverseRowOrder(bool reverseRowOrder);
+ bool getPackReverseRowOrder() const;
+
+ // These create and destroy methods are merely pass-throughs to
+ // ResourceManager, which owns these object types
+ GLuint createBuffer();
+ GLuint createShader(GLenum type);
+ GLuint createProgram();
+ GLuint createTexture();
+ GLuint createRenderbuffer();
+
+ void deleteBuffer(GLuint buffer);
+ void deleteShader(GLuint shader);
+ void deleteProgram(GLuint program);
+ void deleteTexture(GLuint texture);
+ void deleteRenderbuffer(GLuint renderbuffer);
+
+ // Framebuffers are owned by the Context, so these methods do not pass through
+ GLuint createFramebuffer();
+ void deleteFramebuffer(GLuint framebuffer);
+
+ // Fences are owned by the Context.
+ GLuint createFence();
+ void deleteFence(GLuint fence);
+
+ // Queries are owned by the Context;
+ GLuint createQuery();
+ void deleteQuery(GLuint query);
+
+ void bindArrayBuffer(GLuint buffer);
+ void bindElementArrayBuffer(GLuint buffer);
+ void bindTexture2D(GLuint texture);
+ void bindTextureCubeMap(GLuint texture);
+ void bindReadFramebuffer(GLuint framebuffer);
+ void bindDrawFramebuffer(GLuint framebuffer);
+ void bindRenderbuffer(GLuint renderbuffer);
+ void useProgram(GLuint program);
+ void linkProgram(GLuint program);
+ void setProgramBinary(GLuint program, const void *binary, GLint length);
+
+ void beginQuery(GLenum target, GLuint query);
+ void endQuery(GLenum target);
+
+ void setFramebufferZero(Framebuffer *framebuffer);
+
+ void setRenderbufferStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
+
+ void setVertexAttrib(GLuint index, const GLfloat *values);
+ void setVertexAttribDivisor(GLuint index, GLuint divisor);
+
+ Buffer *getBuffer(GLuint handle);
+ Fence *getFence(GLuint handle);
+ Shader *getShader(GLuint handle);
+ Program *getProgram(GLuint handle);
+ Texture *getTexture(GLuint handle);
+ Framebuffer *getFramebuffer(GLuint handle);
+ Renderbuffer *getRenderbuffer(GLuint handle);
+ Query *getQuery(GLuint handle, bool create, GLenum type);
+
+ Buffer *getArrayBuffer();
+ Buffer *getElementArrayBuffer();
+ ProgramBinary *getCurrentProgramBinary();
+ Texture2D *getTexture2D();
+ TextureCubeMap *getTextureCubeMap();
+ Texture *getSamplerTexture(unsigned int sampler, TextureType type);
+ Framebuffer *getReadFramebuffer();
+ Framebuffer *getDrawFramebuffer();
+
+ bool getFloatv(GLenum pname, GLfloat *params);
+ bool getIntegerv(GLenum pname, GLint *params);
+ bool getBooleanv(GLenum pname, GLboolean *params);
+
+ bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams);
+
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels);
+ void clear(GLbitfield mask);
+ void drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances);
+ void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances);
+ void sync(bool block); // flush/finish
+
+ void recordInvalidEnum();
+ void recordInvalidValue();
+ void recordInvalidOperation();
+ void recordOutOfMemory();
+ void recordInvalidFramebufferOperation();
+
+ GLenum getError();
+ GLenum getResetStatus();
+ virtual bool isResetNotificationEnabled();
+
+ int getMajorShaderModel() const;
+ float getMaximumPointSize() const;
+ unsigned int getMaximumCombinedTextureImageUnits() const;
+ int getMaximumRenderbufferDimension() const;
+ int getMaximumTextureDimension() const;
+ int getMaximumCubeTextureDimension() const;
+ int getMaximumTextureLevel() const;
+ unsigned int getMaximumRenderTargets() const;
+ GLsizei getMaxSupportedSamples() const;
+ const char *getExtensionString() const;
+ const char *getRendererString() const;
+ bool supportsEventQueries() const;
+ bool supportsOcclusionQueries() const;
+ bool supportsBGRATextures() const;
+ bool supportsDXT1Textures() const;
+ bool supportsDXT3Textures() const;
+ bool supportsDXT5Textures() const;
+ bool supportsFloat32Textures() const;
+ bool supportsFloat32LinearFilter() const;
+ bool supportsFloat32RenderableTextures() const;
+ bool supportsFloat16Textures() const;
+ bool supportsFloat16LinearFilter() const;
+ bool supportsFloat16RenderableTextures() const;
+ bool supportsLuminanceTextures() const;
+ bool supportsLuminanceAlphaTextures() const;
+ bool supportsDepthTextures() const;
+ bool supports32bitIndices() const;
+ bool supportsNonPower2Texture() const;
+ bool supportsInstancing() const;
+ bool supportsTextureFilterAnisotropy() const;
+
+ bool getCurrentReadFormatType(GLenum *format, GLenum *type);
+
+ float getTextureMaxAnisotropy() const;
+
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Context);
+
+ bool applyRenderTarget(GLenum drawMode, bool ignoreViewport);
+ void applyState(GLenum drawMode);
+ void applyShaders();
+ void applyTextures();
+ void applyTextures(SamplerType type);
+
+ void detachBuffer(GLuint buffer);
+ void detachTexture(GLuint texture);
+ void detachFramebuffer(GLuint framebuffer);
+ void detachRenderbuffer(GLuint renderbuffer);
+
+ Texture *getIncompleteTexture(TextureType type);
+
+ bool skipDraw(GLenum drawMode);
+
+ void initExtensionString();
+ void initRendererString();
+
+ rx::Renderer *const mRenderer;
+
+ State mState;
+
+ BindingPointer<Texture2D> mTexture2DZero;
+ BindingPointer<TextureCubeMap> mTextureCubeMapZero;
+
+#ifndef HASH_MAP
+# ifdef _MSC_VER
+# define HASH_MAP stdext::hash_map
+# else
+# define HASH_MAP std::unordered_map
+# endif
+#endif
+
+ typedef HASH_MAP<GLuint, Framebuffer*> FramebufferMap;
+ FramebufferMap mFramebufferMap;
+ HandleAllocator mFramebufferHandleAllocator;
+
+ typedef HASH_MAP<GLuint, Fence*> FenceMap;
+ FenceMap mFenceMap;
+ HandleAllocator mFenceHandleAllocator;
+
+ typedef HASH_MAP<GLuint, Query*> QueryMap;
+ QueryMap mQueryMap;
+ HandleAllocator mQueryHandleAllocator;
+
+ const char *mExtensionString;
+ const char *mRendererString;
+
+ BindingPointer<Texture> mIncompleteTextures[TEXTURE_TYPE_COUNT];
+
+ // Recorded errors
+ bool mInvalidEnum;
+ bool mInvalidValue;
+ bool mInvalidOperation;
+ bool mOutOfMemory;
+ bool mInvalidFramebufferOperation;
+
+ // Current/lost context flags
+ bool mHasBeenCurrent;
+ bool mContextLost;
+ GLenum mResetStatus;
+ GLenum mResetStrategy;
+ bool mRobustAccess;
+
+ BindingPointer<ProgramBinary> mCurrentProgramBinary;
+ Framebuffer *mBoundDrawFramebuffer;
+
+ int mMajorShaderModel;
+ float mMaximumPointSize;
+ bool mSupportsVertexTexture;
+ bool mSupportsNonPower2Texture;
+ bool mSupportsInstancing;
+ int mMaxViewportDimension;
+ int mMaxRenderbufferDimension;
+ int mMaxTextureDimension;
+ int mMaxCubeTextureDimension;
+ int mMaxTextureLevel;
+ float mMaxTextureAnisotropy;
+ bool mSupportsEventQueries;
+ bool mSupportsOcclusionQueries;
+ bool mSupportsBGRATextures;
+ bool mSupportsDXT1Textures;
+ bool mSupportsDXT3Textures;
+ bool mSupportsDXT5Textures;
+ bool mSupportsFloat32Textures;
+ bool mSupportsFloat32LinearFilter;
+ bool mSupportsFloat32RenderableTextures;
+ bool mSupportsFloat16Textures;
+ bool mSupportsFloat16LinearFilter;
+ bool mSupportsFloat16RenderableTextures;
+ bool mSupportsLuminanceTextures;
+ bool mSupportsLuminanceAlphaTextures;
+ bool mSupportsDepthTextures;
+ bool mSupports32bitIndices;
+ bool mSupportsTextureFilterAnisotropy;
+ int mNumCompressedTextureFormats;
+
+ ResourceManager *mResourceManager;
+};
+}
+
+#endif // INCLUDE_CONTEXT_H_
diff --git a/src/libGLESv2/Fence.cpp b/src/libGLESv2/Fence.cpp
new file mode 100644
index 00000000..e4218bbe
--- /dev/null
+++ b/src/libGLESv2/Fence.cpp
@@ -0,0 +1,52 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension.
+
+#include "libGLESv2/Fence.h"
+#include "libGLESv2/renderer/FenceImpl.h"
+#include "libGLESv2/renderer/Renderer.h"
+
+namespace gl
+{
+
+Fence::Fence(rx::Renderer *renderer)
+{
+ mFence = renderer->createFence();
+}
+
+Fence::~Fence()
+{
+ delete mFence;
+}
+
+GLboolean Fence::isFence()
+{
+ return mFence->isFence();
+}
+
+void Fence::setFence(GLenum condition)
+{
+ mFence->setFence(condition);
+}
+
+GLboolean Fence::testFence()
+{
+ return mFence->testFence();
+}
+
+void Fence::finishFence()
+{
+ mFence->finishFence();
+}
+
+void Fence::getFenceiv(GLenum pname, GLint *params)
+{
+ mFence->getFenceiv(pname, params);
+}
+
+}
diff --git a/src/libGLESv2/Fence.h b/src/libGLESv2/Fence.h
new file mode 100644
index 00000000..1cedebb1
--- /dev/null
+++ b/src/libGLESv2/Fence.h
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Fence.h: Defines the gl::Fence class, which supports the GL_NV_fence extension.
+
+#ifndef LIBGLESV2_FENCE_H_
+#define LIBGLESV2_FENCE_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+class Renderer;
+class FenceImpl;
+}
+
+namespace gl
+{
+
+class Fence
+{
+ public:
+ explicit Fence(rx::Renderer *renderer);
+ virtual ~Fence();
+
+ GLboolean isFence();
+ void setFence(GLenum condition);
+ GLboolean testFence();
+ void finishFence();
+ void getFenceiv(GLenum pname, GLint *params);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Fence);
+
+ rx::FenceImpl *mFence;
+};
+
+}
+
+#endif // LIBGLESV2_FENCE_H_
diff --git a/src/libGLESv2/Float16ToFloat32.cpp b/src/libGLESv2/Float16ToFloat32.cpp
new file mode 100644
index 00000000..b90d2f60
--- /dev/null
+++ b/src/libGLESv2/Float16ToFloat32.cpp
@@ -0,0 +1,2204 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is automatically generated.
+
+namespace gl
+{
+
+const static unsigned g_mantissa[2048] = {
+ 0x00000000,
+ 0x33800000,
+ 0x34000000,
+ 0x34400000,
+ 0x34800000,
+ 0x34a00000,
+ 0x34c00000,
+ 0x34e00000,
+ 0x35000000,
+ 0x35100000,
+ 0x35200000,
+ 0x35300000,
+ 0x35400000,
+ 0x35500000,
+ 0x35600000,
+ 0x35700000,
+ 0x35800000,
+ 0x35880000,
+ 0x35900000,
+ 0x35980000,
+ 0x35a00000,
+ 0x35a80000,
+ 0x35b00000,
+ 0x35b80000,
+ 0x35c00000,
+ 0x35c80000,
+ 0x35d00000,
+ 0x35d80000,
+ 0x35e00000,
+ 0x35e80000,
+ 0x35f00000,
+ 0x35f80000,
+ 0x36000000,
+ 0x36040000,
+ 0x36080000,
+ 0x360c0000,
+ 0x36100000,
+ 0x36140000,
+ 0x36180000,
+ 0x361c0000,
+ 0x36200000,
+ 0x36240000,
+ 0x36280000,
+ 0x362c0000,
+ 0x36300000,
+ 0x36340000,
+ 0x36380000,
+ 0x363c0000,
+ 0x36400000,
+ 0x36440000,
+ 0x36480000,
+ 0x364c0000,
+ 0x36500000,
+ 0x36540000,
+ 0x36580000,
+ 0x365c0000,
+ 0x36600000,
+ 0x36640000,
+ 0x36680000,
+ 0x366c0000,
+ 0x36700000,
+ 0x36740000,
+ 0x36780000,
+ 0x367c0000,
+ 0x36800000,
+ 0x36820000,
+ 0x36840000,
+ 0x36860000,
+ 0x36880000,
+ 0x368a0000,
+ 0x368c0000,
+ 0x368e0000,
+ 0x36900000,
+ 0x36920000,
+ 0x36940000,
+ 0x36960000,
+ 0x36980000,
+ 0x369a0000,
+ 0x369c0000,
+ 0x369e0000,
+ 0x36a00000,
+ 0x36a20000,
+ 0x36a40000,
+ 0x36a60000,
+ 0x36a80000,
+ 0x36aa0000,
+ 0x36ac0000,
+ 0x36ae0000,
+ 0x36b00000,
+ 0x36b20000,
+ 0x36b40000,
+ 0x36b60000,
+ 0x36b80000,
+ 0x36ba0000,
+ 0x36bc0000,
+ 0x36be0000,
+ 0x36c00000,
+ 0x36c20000,
+ 0x36c40000,
+ 0x36c60000,
+ 0x36c80000,
+ 0x36ca0000,
+ 0x36cc0000,
+ 0x36ce0000,
+ 0x36d00000,
+ 0x36d20000,
+ 0x36d40000,
+ 0x36d60000,
+ 0x36d80000,
+ 0x36da0000,
+ 0x36dc0000,
+ 0x36de0000,
+ 0x36e00000,
+ 0x36e20000,
+ 0x36e40000,
+ 0x36e60000,
+ 0x36e80000,
+ 0x36ea0000,
+ 0x36ec0000,
+ 0x36ee0000,
+ 0x36f00000,
+ 0x36f20000,
+ 0x36f40000,
+ 0x36f60000,
+ 0x36f80000,
+ 0x36fa0000,
+ 0x36fc0000,
+ 0x36fe0000,
+ 0x37000000,
+ 0x37010000,
+ 0x37020000,
+ 0x37030000,
+ 0x37040000,
+ 0x37050000,
+ 0x37060000,
+ 0x37070000,
+ 0x37080000,
+ 0x37090000,
+ 0x370a0000,
+ 0x370b0000,
+ 0x370c0000,
+ 0x370d0000,
+ 0x370e0000,
+ 0x370f0000,
+ 0x37100000,
+ 0x37110000,
+ 0x37120000,
+ 0x37130000,
+ 0x37140000,
+ 0x37150000,
+ 0x37160000,
+ 0x37170000,
+ 0x37180000,
+ 0x37190000,
+ 0x371a0000,
+ 0x371b0000,
+ 0x371c0000,
+ 0x371d0000,
+ 0x371e0000,
+ 0x371f0000,
+ 0x37200000,
+ 0x37210000,
+ 0x37220000,
+ 0x37230000,
+ 0x37240000,
+ 0x37250000,
+ 0x37260000,
+ 0x37270000,
+ 0x37280000,
+ 0x37290000,
+ 0x372a0000,
+ 0x372b0000,
+ 0x372c0000,
+ 0x372d0000,
+ 0x372e0000,
+ 0x372f0000,
+ 0x37300000,
+ 0x37310000,
+ 0x37320000,
+ 0x37330000,
+ 0x37340000,
+ 0x37350000,
+ 0x37360000,
+ 0x37370000,
+ 0x37380000,
+ 0x37390000,
+ 0x373a0000,
+ 0x373b0000,
+ 0x373c0000,
+ 0x373d0000,
+ 0x373e0000,
+ 0x373f0000,
+ 0x37400000,
+ 0x37410000,
+ 0x37420000,
+ 0x37430000,
+ 0x37440000,
+ 0x37450000,
+ 0x37460000,
+ 0x37470000,
+ 0x37480000,
+ 0x37490000,
+ 0x374a0000,
+ 0x374b0000,
+ 0x374c0000,
+ 0x374d0000,
+ 0x374e0000,
+ 0x374f0000,
+ 0x37500000,
+ 0x37510000,
+ 0x37520000,
+ 0x37530000,
+ 0x37540000,
+ 0x37550000,
+ 0x37560000,
+ 0x37570000,
+ 0x37580000,
+ 0x37590000,
+ 0x375a0000,
+ 0x375b0000,
+ 0x375c0000,
+ 0x375d0000,
+ 0x375e0000,
+ 0x375f0000,
+ 0x37600000,
+ 0x37610000,
+ 0x37620000,
+ 0x37630000,
+ 0x37640000,
+ 0x37650000,
+ 0x37660000,
+ 0x37670000,
+ 0x37680000,
+ 0x37690000,
+ 0x376a0000,
+ 0x376b0000,
+ 0x376c0000,
+ 0x376d0000,
+ 0x376e0000,
+ 0x376f0000,
+ 0x37700000,
+ 0x37710000,
+ 0x37720000,
+ 0x37730000,
+ 0x37740000,
+ 0x37750000,
+ 0x37760000,
+ 0x37770000,
+ 0x37780000,
+ 0x37790000,
+ 0x377a0000,
+ 0x377b0000,
+ 0x377c0000,
+ 0x377d0000,
+ 0x377e0000,
+ 0x377f0000,
+ 0x37800000,
+ 0x37808000,
+ 0x37810000,
+ 0x37818000,
+ 0x37820000,
+ 0x37828000,
+ 0x37830000,
+ 0x37838000,
+ 0x37840000,
+ 0x37848000,
+ 0x37850000,
+ 0x37858000,
+ 0x37860000,
+ 0x37868000,
+ 0x37870000,
+ 0x37878000,
+ 0x37880000,
+ 0x37888000,
+ 0x37890000,
+ 0x37898000,
+ 0x378a0000,
+ 0x378a8000,
+ 0x378b0000,
+ 0x378b8000,
+ 0x378c0000,
+ 0x378c8000,
+ 0x378d0000,
+ 0x378d8000,
+ 0x378e0000,
+ 0x378e8000,
+ 0x378f0000,
+ 0x378f8000,
+ 0x37900000,
+ 0x37908000,
+ 0x37910000,
+ 0x37918000,
+ 0x37920000,
+ 0x37928000,
+ 0x37930000,
+ 0x37938000,
+ 0x37940000,
+ 0x37948000,
+ 0x37950000,
+ 0x37958000,
+ 0x37960000,
+ 0x37968000,
+ 0x37970000,
+ 0x37978000,
+ 0x37980000,
+ 0x37988000,
+ 0x37990000,
+ 0x37998000,
+ 0x379a0000,
+ 0x379a8000,
+ 0x379b0000,
+ 0x379b8000,
+ 0x379c0000,
+ 0x379c8000,
+ 0x379d0000,
+ 0x379d8000,
+ 0x379e0000,
+ 0x379e8000,
+ 0x379f0000,
+ 0x379f8000,
+ 0x37a00000,
+ 0x37a08000,
+ 0x37a10000,
+ 0x37a18000,
+ 0x37a20000,
+ 0x37a28000,
+ 0x37a30000,
+ 0x37a38000,
+ 0x37a40000,
+ 0x37a48000,
+ 0x37a50000,
+ 0x37a58000,
+ 0x37a60000,
+ 0x37a68000,
+ 0x37a70000,
+ 0x37a78000,
+ 0x37a80000,
+ 0x37a88000,
+ 0x37a90000,
+ 0x37a98000,
+ 0x37aa0000,
+ 0x37aa8000,
+ 0x37ab0000,
+ 0x37ab8000,
+ 0x37ac0000,
+ 0x37ac8000,
+ 0x37ad0000,
+ 0x37ad8000,
+ 0x37ae0000,
+ 0x37ae8000,
+ 0x37af0000,
+ 0x37af8000,
+ 0x37b00000,
+ 0x37b08000,
+ 0x37b10000,
+ 0x37b18000,
+ 0x37b20000,
+ 0x37b28000,
+ 0x37b30000,
+ 0x37b38000,
+ 0x37b40000,
+ 0x37b48000,
+ 0x37b50000,
+ 0x37b58000,
+ 0x37b60000,
+ 0x37b68000,
+ 0x37b70000,
+ 0x37b78000,
+ 0x37b80000,
+ 0x37b88000,
+ 0x37b90000,
+ 0x37b98000,
+ 0x37ba0000,
+ 0x37ba8000,
+ 0x37bb0000,
+ 0x37bb8000,
+ 0x37bc0000,
+ 0x37bc8000,
+ 0x37bd0000,
+ 0x37bd8000,
+ 0x37be0000,
+ 0x37be8000,
+ 0x37bf0000,
+ 0x37bf8000,
+ 0x37c00000,
+ 0x37c08000,
+ 0x37c10000,
+ 0x37c18000,
+ 0x37c20000,
+ 0x37c28000,
+ 0x37c30000,
+ 0x37c38000,
+ 0x37c40000,
+ 0x37c48000,
+ 0x37c50000,
+ 0x37c58000,
+ 0x37c60000,
+ 0x37c68000,
+ 0x37c70000,
+ 0x37c78000,
+ 0x37c80000,
+ 0x37c88000,
+ 0x37c90000,
+ 0x37c98000,
+ 0x37ca0000,
+ 0x37ca8000,
+ 0x37cb0000,
+ 0x37cb8000,
+ 0x37cc0000,
+ 0x37cc8000,
+ 0x37cd0000,
+ 0x37cd8000,
+ 0x37ce0000,
+ 0x37ce8000,
+ 0x37cf0000,
+ 0x37cf8000,
+ 0x37d00000,
+ 0x37d08000,
+ 0x37d10000,
+ 0x37d18000,
+ 0x37d20000,
+ 0x37d28000,
+ 0x37d30000,
+ 0x37d38000,
+ 0x37d40000,
+ 0x37d48000,
+ 0x37d50000,
+ 0x37d58000,
+ 0x37d60000,
+ 0x37d68000,
+ 0x37d70000,
+ 0x37d78000,
+ 0x37d80000,
+ 0x37d88000,
+ 0x37d90000,
+ 0x37d98000,
+ 0x37da0000,
+ 0x37da8000,
+ 0x37db0000,
+ 0x37db8000,
+ 0x37dc0000,
+ 0x37dc8000,
+ 0x37dd0000,
+ 0x37dd8000,
+ 0x37de0000,
+ 0x37de8000,
+ 0x37df0000,
+ 0x37df8000,
+ 0x37e00000,
+ 0x37e08000,
+ 0x37e10000,
+ 0x37e18000,
+ 0x37e20000,
+ 0x37e28000,
+ 0x37e30000,
+ 0x37e38000,
+ 0x37e40000,
+ 0x37e48000,
+ 0x37e50000,
+ 0x37e58000,
+ 0x37e60000,
+ 0x37e68000,
+ 0x37e70000,
+ 0x37e78000,
+ 0x37e80000,
+ 0x37e88000,
+ 0x37e90000,
+ 0x37e98000,
+ 0x37ea0000,
+ 0x37ea8000,
+ 0x37eb0000,
+ 0x37eb8000,
+ 0x37ec0000,
+ 0x37ec8000,
+ 0x37ed0000,
+ 0x37ed8000,
+ 0x37ee0000,
+ 0x37ee8000,
+ 0x37ef0000,
+ 0x37ef8000,
+ 0x37f00000,
+ 0x37f08000,
+ 0x37f10000,
+ 0x37f18000,
+ 0x37f20000,
+ 0x37f28000,
+ 0x37f30000,
+ 0x37f38000,
+ 0x37f40000,
+ 0x37f48000,
+ 0x37f50000,
+ 0x37f58000,
+ 0x37f60000,
+ 0x37f68000,
+ 0x37f70000,
+ 0x37f78000,
+ 0x37f80000,
+ 0x37f88000,
+ 0x37f90000,
+ 0x37f98000,
+ 0x37fa0000,
+ 0x37fa8000,
+ 0x37fb0000,
+ 0x37fb8000,
+ 0x37fc0000,
+ 0x37fc8000,
+ 0x37fd0000,
+ 0x37fd8000,
+ 0x37fe0000,
+ 0x37fe8000,
+ 0x37ff0000,
+ 0x37ff8000,
+ 0x38000000,
+ 0x38004000,
+ 0x38008000,
+ 0x3800c000,
+ 0x38010000,
+ 0x38014000,
+ 0x38018000,
+ 0x3801c000,
+ 0x38020000,
+ 0x38024000,
+ 0x38028000,
+ 0x3802c000,
+ 0x38030000,
+ 0x38034000,
+ 0x38038000,
+ 0x3803c000,
+ 0x38040000,
+ 0x38044000,
+ 0x38048000,
+ 0x3804c000,
+ 0x38050000,
+ 0x38054000,
+ 0x38058000,
+ 0x3805c000,
+ 0x38060000,
+ 0x38064000,
+ 0x38068000,
+ 0x3806c000,
+ 0x38070000,
+ 0x38074000,
+ 0x38078000,
+ 0x3807c000,
+ 0x38080000,
+ 0x38084000,
+ 0x38088000,
+ 0x3808c000,
+ 0x38090000,
+ 0x38094000,
+ 0x38098000,
+ 0x3809c000,
+ 0x380a0000,
+ 0x380a4000,
+ 0x380a8000,
+ 0x380ac000,
+ 0x380b0000,
+ 0x380b4000,
+ 0x380b8000,
+ 0x380bc000,
+ 0x380c0000,
+ 0x380c4000,
+ 0x380c8000,
+ 0x380cc000,
+ 0x380d0000,
+ 0x380d4000,
+ 0x380d8000,
+ 0x380dc000,
+ 0x380e0000,
+ 0x380e4000,
+ 0x380e8000,
+ 0x380ec000,
+ 0x380f0000,
+ 0x380f4000,
+ 0x380f8000,
+ 0x380fc000,
+ 0x38100000,
+ 0x38104000,
+ 0x38108000,
+ 0x3810c000,
+ 0x38110000,
+ 0x38114000,
+ 0x38118000,
+ 0x3811c000,
+ 0x38120000,
+ 0x38124000,
+ 0x38128000,
+ 0x3812c000,
+ 0x38130000,
+ 0x38134000,
+ 0x38138000,
+ 0x3813c000,
+ 0x38140000,
+ 0x38144000,
+ 0x38148000,
+ 0x3814c000,
+ 0x38150000,
+ 0x38154000,
+ 0x38158000,
+ 0x3815c000,
+ 0x38160000,
+ 0x38164000,
+ 0x38168000,
+ 0x3816c000,
+ 0x38170000,
+ 0x38174000,
+ 0x38178000,
+ 0x3817c000,
+ 0x38180000,
+ 0x38184000,
+ 0x38188000,
+ 0x3818c000,
+ 0x38190000,
+ 0x38194000,
+ 0x38198000,
+ 0x3819c000,
+ 0x381a0000,
+ 0x381a4000,
+ 0x381a8000,
+ 0x381ac000,
+ 0x381b0000,
+ 0x381b4000,
+ 0x381b8000,
+ 0x381bc000,
+ 0x381c0000,
+ 0x381c4000,
+ 0x381c8000,
+ 0x381cc000,
+ 0x381d0000,
+ 0x381d4000,
+ 0x381d8000,
+ 0x381dc000,
+ 0x381e0000,
+ 0x381e4000,
+ 0x381e8000,
+ 0x381ec000,
+ 0x381f0000,
+ 0x381f4000,
+ 0x381f8000,
+ 0x381fc000,
+ 0x38200000,
+ 0x38204000,
+ 0x38208000,
+ 0x3820c000,
+ 0x38210000,
+ 0x38214000,
+ 0x38218000,
+ 0x3821c000,
+ 0x38220000,
+ 0x38224000,
+ 0x38228000,
+ 0x3822c000,
+ 0x38230000,
+ 0x38234000,
+ 0x38238000,
+ 0x3823c000,
+ 0x38240000,
+ 0x38244000,
+ 0x38248000,
+ 0x3824c000,
+ 0x38250000,
+ 0x38254000,
+ 0x38258000,
+ 0x3825c000,
+ 0x38260000,
+ 0x38264000,
+ 0x38268000,
+ 0x3826c000,
+ 0x38270000,
+ 0x38274000,
+ 0x38278000,
+ 0x3827c000,
+ 0x38280000,
+ 0x38284000,
+ 0x38288000,
+ 0x3828c000,
+ 0x38290000,
+ 0x38294000,
+ 0x38298000,
+ 0x3829c000,
+ 0x382a0000,
+ 0x382a4000,
+ 0x382a8000,
+ 0x382ac000,
+ 0x382b0000,
+ 0x382b4000,
+ 0x382b8000,
+ 0x382bc000,
+ 0x382c0000,
+ 0x382c4000,
+ 0x382c8000,
+ 0x382cc000,
+ 0x382d0000,
+ 0x382d4000,
+ 0x382d8000,
+ 0x382dc000,
+ 0x382e0000,
+ 0x382e4000,
+ 0x382e8000,
+ 0x382ec000,
+ 0x382f0000,
+ 0x382f4000,
+ 0x382f8000,
+ 0x382fc000,
+ 0x38300000,
+ 0x38304000,
+ 0x38308000,
+ 0x3830c000,
+ 0x38310000,
+ 0x38314000,
+ 0x38318000,
+ 0x3831c000,
+ 0x38320000,
+ 0x38324000,
+ 0x38328000,
+ 0x3832c000,
+ 0x38330000,
+ 0x38334000,
+ 0x38338000,
+ 0x3833c000,
+ 0x38340000,
+ 0x38344000,
+ 0x38348000,
+ 0x3834c000,
+ 0x38350000,
+ 0x38354000,
+ 0x38358000,
+ 0x3835c000,
+ 0x38360000,
+ 0x38364000,
+ 0x38368000,
+ 0x3836c000,
+ 0x38370000,
+ 0x38374000,
+ 0x38378000,
+ 0x3837c000,
+ 0x38380000,
+ 0x38384000,
+ 0x38388000,
+ 0x3838c000,
+ 0x38390000,
+ 0x38394000,
+ 0x38398000,
+ 0x3839c000,
+ 0x383a0000,
+ 0x383a4000,
+ 0x383a8000,
+ 0x383ac000,
+ 0x383b0000,
+ 0x383b4000,
+ 0x383b8000,
+ 0x383bc000,
+ 0x383c0000,
+ 0x383c4000,
+ 0x383c8000,
+ 0x383cc000,
+ 0x383d0000,
+ 0x383d4000,
+ 0x383d8000,
+ 0x383dc000,
+ 0x383e0000,
+ 0x383e4000,
+ 0x383e8000,
+ 0x383ec000,
+ 0x383f0000,
+ 0x383f4000,
+ 0x383f8000,
+ 0x383fc000,
+ 0x38400000,
+ 0x38404000,
+ 0x38408000,
+ 0x3840c000,
+ 0x38410000,
+ 0x38414000,
+ 0x38418000,
+ 0x3841c000,
+ 0x38420000,
+ 0x38424000,
+ 0x38428000,
+ 0x3842c000,
+ 0x38430000,
+ 0x38434000,
+ 0x38438000,
+ 0x3843c000,
+ 0x38440000,
+ 0x38444000,
+ 0x38448000,
+ 0x3844c000,
+ 0x38450000,
+ 0x38454000,
+ 0x38458000,
+ 0x3845c000,
+ 0x38460000,
+ 0x38464000,
+ 0x38468000,
+ 0x3846c000,
+ 0x38470000,
+ 0x38474000,
+ 0x38478000,
+ 0x3847c000,
+ 0x38480000,
+ 0x38484000,
+ 0x38488000,
+ 0x3848c000,
+ 0x38490000,
+ 0x38494000,
+ 0x38498000,
+ 0x3849c000,
+ 0x384a0000,
+ 0x384a4000,
+ 0x384a8000,
+ 0x384ac000,
+ 0x384b0000,
+ 0x384b4000,
+ 0x384b8000,
+ 0x384bc000,
+ 0x384c0000,
+ 0x384c4000,
+ 0x384c8000,
+ 0x384cc000,
+ 0x384d0000,
+ 0x384d4000,
+ 0x384d8000,
+ 0x384dc000,
+ 0x384e0000,
+ 0x384e4000,
+ 0x384e8000,
+ 0x384ec000,
+ 0x384f0000,
+ 0x384f4000,
+ 0x384f8000,
+ 0x384fc000,
+ 0x38500000,
+ 0x38504000,
+ 0x38508000,
+ 0x3850c000,
+ 0x38510000,
+ 0x38514000,
+ 0x38518000,
+ 0x3851c000,
+ 0x38520000,
+ 0x38524000,
+ 0x38528000,
+ 0x3852c000,
+ 0x38530000,
+ 0x38534000,
+ 0x38538000,
+ 0x3853c000,
+ 0x38540000,
+ 0x38544000,
+ 0x38548000,
+ 0x3854c000,
+ 0x38550000,
+ 0x38554000,
+ 0x38558000,
+ 0x3855c000,
+ 0x38560000,
+ 0x38564000,
+ 0x38568000,
+ 0x3856c000,
+ 0x38570000,
+ 0x38574000,
+ 0x38578000,
+ 0x3857c000,
+ 0x38580000,
+ 0x38584000,
+ 0x38588000,
+ 0x3858c000,
+ 0x38590000,
+ 0x38594000,
+ 0x38598000,
+ 0x3859c000,
+ 0x385a0000,
+ 0x385a4000,
+ 0x385a8000,
+ 0x385ac000,
+ 0x385b0000,
+ 0x385b4000,
+ 0x385b8000,
+ 0x385bc000,
+ 0x385c0000,
+ 0x385c4000,
+ 0x385c8000,
+ 0x385cc000,
+ 0x385d0000,
+ 0x385d4000,
+ 0x385d8000,
+ 0x385dc000,
+ 0x385e0000,
+ 0x385e4000,
+ 0x385e8000,
+ 0x385ec000,
+ 0x385f0000,
+ 0x385f4000,
+ 0x385f8000,
+ 0x385fc000,
+ 0x38600000,
+ 0x38604000,
+ 0x38608000,
+ 0x3860c000,
+ 0x38610000,
+ 0x38614000,
+ 0x38618000,
+ 0x3861c000,
+ 0x38620000,
+ 0x38624000,
+ 0x38628000,
+ 0x3862c000,
+ 0x38630000,
+ 0x38634000,
+ 0x38638000,
+ 0x3863c000,
+ 0x38640000,
+ 0x38644000,
+ 0x38648000,
+ 0x3864c000,
+ 0x38650000,
+ 0x38654000,
+ 0x38658000,
+ 0x3865c000,
+ 0x38660000,
+ 0x38664000,
+ 0x38668000,
+ 0x3866c000,
+ 0x38670000,
+ 0x38674000,
+ 0x38678000,
+ 0x3867c000,
+ 0x38680000,
+ 0x38684000,
+ 0x38688000,
+ 0x3868c000,
+ 0x38690000,
+ 0x38694000,
+ 0x38698000,
+ 0x3869c000,
+ 0x386a0000,
+ 0x386a4000,
+ 0x386a8000,
+ 0x386ac000,
+ 0x386b0000,
+ 0x386b4000,
+ 0x386b8000,
+ 0x386bc000,
+ 0x386c0000,
+ 0x386c4000,
+ 0x386c8000,
+ 0x386cc000,
+ 0x386d0000,
+ 0x386d4000,
+ 0x386d8000,
+ 0x386dc000,
+ 0x386e0000,
+ 0x386e4000,
+ 0x386e8000,
+ 0x386ec000,
+ 0x386f0000,
+ 0x386f4000,
+ 0x386f8000,
+ 0x386fc000,
+ 0x38700000,
+ 0x38704000,
+ 0x38708000,
+ 0x3870c000,
+ 0x38710000,
+ 0x38714000,
+ 0x38718000,
+ 0x3871c000,
+ 0x38720000,
+ 0x38724000,
+ 0x38728000,
+ 0x3872c000,
+ 0x38730000,
+ 0x38734000,
+ 0x38738000,
+ 0x3873c000,
+ 0x38740000,
+ 0x38744000,
+ 0x38748000,
+ 0x3874c000,
+ 0x38750000,
+ 0x38754000,
+ 0x38758000,
+ 0x3875c000,
+ 0x38760000,
+ 0x38764000,
+ 0x38768000,
+ 0x3876c000,
+ 0x38770000,
+ 0x38774000,
+ 0x38778000,
+ 0x3877c000,
+ 0x38780000,
+ 0x38784000,
+ 0x38788000,
+ 0x3878c000,
+ 0x38790000,
+ 0x38794000,
+ 0x38798000,
+ 0x3879c000,
+ 0x387a0000,
+ 0x387a4000,
+ 0x387a8000,
+ 0x387ac000,
+ 0x387b0000,
+ 0x387b4000,
+ 0x387b8000,
+ 0x387bc000,
+ 0x387c0000,
+ 0x387c4000,
+ 0x387c8000,
+ 0x387cc000,
+ 0x387d0000,
+ 0x387d4000,
+ 0x387d8000,
+ 0x387dc000,
+ 0x387e0000,
+ 0x387e4000,
+ 0x387e8000,
+ 0x387ec000,
+ 0x387f0000,
+ 0x387f4000,
+ 0x387f8000,
+ 0x387fc000,
+ 0x38000000,
+ 0x38002000,
+ 0x38004000,
+ 0x38006000,
+ 0x38008000,
+ 0x3800a000,
+ 0x3800c000,
+ 0x3800e000,
+ 0x38010000,
+ 0x38012000,
+ 0x38014000,
+ 0x38016000,
+ 0x38018000,
+ 0x3801a000,
+ 0x3801c000,
+ 0x3801e000,
+ 0x38020000,
+ 0x38022000,
+ 0x38024000,
+ 0x38026000,
+ 0x38028000,
+ 0x3802a000,
+ 0x3802c000,
+ 0x3802e000,
+ 0x38030000,
+ 0x38032000,
+ 0x38034000,
+ 0x38036000,
+ 0x38038000,
+ 0x3803a000,
+ 0x3803c000,
+ 0x3803e000,
+ 0x38040000,
+ 0x38042000,
+ 0x38044000,
+ 0x38046000,
+ 0x38048000,
+ 0x3804a000,
+ 0x3804c000,
+ 0x3804e000,
+ 0x38050000,
+ 0x38052000,
+ 0x38054000,
+ 0x38056000,
+ 0x38058000,
+ 0x3805a000,
+ 0x3805c000,
+ 0x3805e000,
+ 0x38060000,
+ 0x38062000,
+ 0x38064000,
+ 0x38066000,
+ 0x38068000,
+ 0x3806a000,
+ 0x3806c000,
+ 0x3806e000,
+ 0x38070000,
+ 0x38072000,
+ 0x38074000,
+ 0x38076000,
+ 0x38078000,
+ 0x3807a000,
+ 0x3807c000,
+ 0x3807e000,
+ 0x38080000,
+ 0x38082000,
+ 0x38084000,
+ 0x38086000,
+ 0x38088000,
+ 0x3808a000,
+ 0x3808c000,
+ 0x3808e000,
+ 0x38090000,
+ 0x38092000,
+ 0x38094000,
+ 0x38096000,
+ 0x38098000,
+ 0x3809a000,
+ 0x3809c000,
+ 0x3809e000,
+ 0x380a0000,
+ 0x380a2000,
+ 0x380a4000,
+ 0x380a6000,
+ 0x380a8000,
+ 0x380aa000,
+ 0x380ac000,
+ 0x380ae000,
+ 0x380b0000,
+ 0x380b2000,
+ 0x380b4000,
+ 0x380b6000,
+ 0x380b8000,
+ 0x380ba000,
+ 0x380bc000,
+ 0x380be000,
+ 0x380c0000,
+ 0x380c2000,
+ 0x380c4000,
+ 0x380c6000,
+ 0x380c8000,
+ 0x380ca000,
+ 0x380cc000,
+ 0x380ce000,
+ 0x380d0000,
+ 0x380d2000,
+ 0x380d4000,
+ 0x380d6000,
+ 0x380d8000,
+ 0x380da000,
+ 0x380dc000,
+ 0x380de000,
+ 0x380e0000,
+ 0x380e2000,
+ 0x380e4000,
+ 0x380e6000,
+ 0x380e8000,
+ 0x380ea000,
+ 0x380ec000,
+ 0x380ee000,
+ 0x380f0000,
+ 0x380f2000,
+ 0x380f4000,
+ 0x380f6000,
+ 0x380f8000,
+ 0x380fa000,
+ 0x380fc000,
+ 0x380fe000,
+ 0x38100000,
+ 0x38102000,
+ 0x38104000,
+ 0x38106000,
+ 0x38108000,
+ 0x3810a000,
+ 0x3810c000,
+ 0x3810e000,
+ 0x38110000,
+ 0x38112000,
+ 0x38114000,
+ 0x38116000,
+ 0x38118000,
+ 0x3811a000,
+ 0x3811c000,
+ 0x3811e000,
+ 0x38120000,
+ 0x38122000,
+ 0x38124000,
+ 0x38126000,
+ 0x38128000,
+ 0x3812a000,
+ 0x3812c000,
+ 0x3812e000,
+ 0x38130000,
+ 0x38132000,
+ 0x38134000,
+ 0x38136000,
+ 0x38138000,
+ 0x3813a000,
+ 0x3813c000,
+ 0x3813e000,
+ 0x38140000,
+ 0x38142000,
+ 0x38144000,
+ 0x38146000,
+ 0x38148000,
+ 0x3814a000,
+ 0x3814c000,
+ 0x3814e000,
+ 0x38150000,
+ 0x38152000,
+ 0x38154000,
+ 0x38156000,
+ 0x38158000,
+ 0x3815a000,
+ 0x3815c000,
+ 0x3815e000,
+ 0x38160000,
+ 0x38162000,
+ 0x38164000,
+ 0x38166000,
+ 0x38168000,
+ 0x3816a000,
+ 0x3816c000,
+ 0x3816e000,
+ 0x38170000,
+ 0x38172000,
+ 0x38174000,
+ 0x38176000,
+ 0x38178000,
+ 0x3817a000,
+ 0x3817c000,
+ 0x3817e000,
+ 0x38180000,
+ 0x38182000,
+ 0x38184000,
+ 0x38186000,
+ 0x38188000,
+ 0x3818a000,
+ 0x3818c000,
+ 0x3818e000,
+ 0x38190000,
+ 0x38192000,
+ 0x38194000,
+ 0x38196000,
+ 0x38198000,
+ 0x3819a000,
+ 0x3819c000,
+ 0x3819e000,
+ 0x381a0000,
+ 0x381a2000,
+ 0x381a4000,
+ 0x381a6000,
+ 0x381a8000,
+ 0x381aa000,
+ 0x381ac000,
+ 0x381ae000,
+ 0x381b0000,
+ 0x381b2000,
+ 0x381b4000,
+ 0x381b6000,
+ 0x381b8000,
+ 0x381ba000,
+ 0x381bc000,
+ 0x381be000,
+ 0x381c0000,
+ 0x381c2000,
+ 0x381c4000,
+ 0x381c6000,
+ 0x381c8000,
+ 0x381ca000,
+ 0x381cc000,
+ 0x381ce000,
+ 0x381d0000,
+ 0x381d2000,
+ 0x381d4000,
+ 0x381d6000,
+ 0x381d8000,
+ 0x381da000,
+ 0x381dc000,
+ 0x381de000,
+ 0x381e0000,
+ 0x381e2000,
+ 0x381e4000,
+ 0x381e6000,
+ 0x381e8000,
+ 0x381ea000,
+ 0x381ec000,
+ 0x381ee000,
+ 0x381f0000,
+ 0x381f2000,
+ 0x381f4000,
+ 0x381f6000,
+ 0x381f8000,
+ 0x381fa000,
+ 0x381fc000,
+ 0x381fe000,
+ 0x38200000,
+ 0x38202000,
+ 0x38204000,
+ 0x38206000,
+ 0x38208000,
+ 0x3820a000,
+ 0x3820c000,
+ 0x3820e000,
+ 0x38210000,
+ 0x38212000,
+ 0x38214000,
+ 0x38216000,
+ 0x38218000,
+ 0x3821a000,
+ 0x3821c000,
+ 0x3821e000,
+ 0x38220000,
+ 0x38222000,
+ 0x38224000,
+ 0x38226000,
+ 0x38228000,
+ 0x3822a000,
+ 0x3822c000,
+ 0x3822e000,
+ 0x38230000,
+ 0x38232000,
+ 0x38234000,
+ 0x38236000,
+ 0x38238000,
+ 0x3823a000,
+ 0x3823c000,
+ 0x3823e000,
+ 0x38240000,
+ 0x38242000,
+ 0x38244000,
+ 0x38246000,
+ 0x38248000,
+ 0x3824a000,
+ 0x3824c000,
+ 0x3824e000,
+ 0x38250000,
+ 0x38252000,
+ 0x38254000,
+ 0x38256000,
+ 0x38258000,
+ 0x3825a000,
+ 0x3825c000,
+ 0x3825e000,
+ 0x38260000,
+ 0x38262000,
+ 0x38264000,
+ 0x38266000,
+ 0x38268000,
+ 0x3826a000,
+ 0x3826c000,
+ 0x3826e000,
+ 0x38270000,
+ 0x38272000,
+ 0x38274000,
+ 0x38276000,
+ 0x38278000,
+ 0x3827a000,
+ 0x3827c000,
+ 0x3827e000,
+ 0x38280000,
+ 0x38282000,
+ 0x38284000,
+ 0x38286000,
+ 0x38288000,
+ 0x3828a000,
+ 0x3828c000,
+ 0x3828e000,
+ 0x38290000,
+ 0x38292000,
+ 0x38294000,
+ 0x38296000,
+ 0x38298000,
+ 0x3829a000,
+ 0x3829c000,
+ 0x3829e000,
+ 0x382a0000,
+ 0x382a2000,
+ 0x382a4000,
+ 0x382a6000,
+ 0x382a8000,
+ 0x382aa000,
+ 0x382ac000,
+ 0x382ae000,
+ 0x382b0000,
+ 0x382b2000,
+ 0x382b4000,
+ 0x382b6000,
+ 0x382b8000,
+ 0x382ba000,
+ 0x382bc000,
+ 0x382be000,
+ 0x382c0000,
+ 0x382c2000,
+ 0x382c4000,
+ 0x382c6000,
+ 0x382c8000,
+ 0x382ca000,
+ 0x382cc000,
+ 0x382ce000,
+ 0x382d0000,
+ 0x382d2000,
+ 0x382d4000,
+ 0x382d6000,
+ 0x382d8000,
+ 0x382da000,
+ 0x382dc000,
+ 0x382de000,
+ 0x382e0000,
+ 0x382e2000,
+ 0x382e4000,
+ 0x382e6000,
+ 0x382e8000,
+ 0x382ea000,
+ 0x382ec000,
+ 0x382ee000,
+ 0x382f0000,
+ 0x382f2000,
+ 0x382f4000,
+ 0x382f6000,
+ 0x382f8000,
+ 0x382fa000,
+ 0x382fc000,
+ 0x382fe000,
+ 0x38300000,
+ 0x38302000,
+ 0x38304000,
+ 0x38306000,
+ 0x38308000,
+ 0x3830a000,
+ 0x3830c000,
+ 0x3830e000,
+ 0x38310000,
+ 0x38312000,
+ 0x38314000,
+ 0x38316000,
+ 0x38318000,
+ 0x3831a000,
+ 0x3831c000,
+ 0x3831e000,
+ 0x38320000,
+ 0x38322000,
+ 0x38324000,
+ 0x38326000,
+ 0x38328000,
+ 0x3832a000,
+ 0x3832c000,
+ 0x3832e000,
+ 0x38330000,
+ 0x38332000,
+ 0x38334000,
+ 0x38336000,
+ 0x38338000,
+ 0x3833a000,
+ 0x3833c000,
+ 0x3833e000,
+ 0x38340000,
+ 0x38342000,
+ 0x38344000,
+ 0x38346000,
+ 0x38348000,
+ 0x3834a000,
+ 0x3834c000,
+ 0x3834e000,
+ 0x38350000,
+ 0x38352000,
+ 0x38354000,
+ 0x38356000,
+ 0x38358000,
+ 0x3835a000,
+ 0x3835c000,
+ 0x3835e000,
+ 0x38360000,
+ 0x38362000,
+ 0x38364000,
+ 0x38366000,
+ 0x38368000,
+ 0x3836a000,
+ 0x3836c000,
+ 0x3836e000,
+ 0x38370000,
+ 0x38372000,
+ 0x38374000,
+ 0x38376000,
+ 0x38378000,
+ 0x3837a000,
+ 0x3837c000,
+ 0x3837e000,
+ 0x38380000,
+ 0x38382000,
+ 0x38384000,
+ 0x38386000,
+ 0x38388000,
+ 0x3838a000,
+ 0x3838c000,
+ 0x3838e000,
+ 0x38390000,
+ 0x38392000,
+ 0x38394000,
+ 0x38396000,
+ 0x38398000,
+ 0x3839a000,
+ 0x3839c000,
+ 0x3839e000,
+ 0x383a0000,
+ 0x383a2000,
+ 0x383a4000,
+ 0x383a6000,
+ 0x383a8000,
+ 0x383aa000,
+ 0x383ac000,
+ 0x383ae000,
+ 0x383b0000,
+ 0x383b2000,
+ 0x383b4000,
+ 0x383b6000,
+ 0x383b8000,
+ 0x383ba000,
+ 0x383bc000,
+ 0x383be000,
+ 0x383c0000,
+ 0x383c2000,
+ 0x383c4000,
+ 0x383c6000,
+ 0x383c8000,
+ 0x383ca000,
+ 0x383cc000,
+ 0x383ce000,
+ 0x383d0000,
+ 0x383d2000,
+ 0x383d4000,
+ 0x383d6000,
+ 0x383d8000,
+ 0x383da000,
+ 0x383dc000,
+ 0x383de000,
+ 0x383e0000,
+ 0x383e2000,
+ 0x383e4000,
+ 0x383e6000,
+ 0x383e8000,
+ 0x383ea000,
+ 0x383ec000,
+ 0x383ee000,
+ 0x383f0000,
+ 0x383f2000,
+ 0x383f4000,
+ 0x383f6000,
+ 0x383f8000,
+ 0x383fa000,
+ 0x383fc000,
+ 0x383fe000,
+ 0x38400000,
+ 0x38402000,
+ 0x38404000,
+ 0x38406000,
+ 0x38408000,
+ 0x3840a000,
+ 0x3840c000,
+ 0x3840e000,
+ 0x38410000,
+ 0x38412000,
+ 0x38414000,
+ 0x38416000,
+ 0x38418000,
+ 0x3841a000,
+ 0x3841c000,
+ 0x3841e000,
+ 0x38420000,
+ 0x38422000,
+ 0x38424000,
+ 0x38426000,
+ 0x38428000,
+ 0x3842a000,
+ 0x3842c000,
+ 0x3842e000,
+ 0x38430000,
+ 0x38432000,
+ 0x38434000,
+ 0x38436000,
+ 0x38438000,
+ 0x3843a000,
+ 0x3843c000,
+ 0x3843e000,
+ 0x38440000,
+ 0x38442000,
+ 0x38444000,
+ 0x38446000,
+ 0x38448000,
+ 0x3844a000,
+ 0x3844c000,
+ 0x3844e000,
+ 0x38450000,
+ 0x38452000,
+ 0x38454000,
+ 0x38456000,
+ 0x38458000,
+ 0x3845a000,
+ 0x3845c000,
+ 0x3845e000,
+ 0x38460000,
+ 0x38462000,
+ 0x38464000,
+ 0x38466000,
+ 0x38468000,
+ 0x3846a000,
+ 0x3846c000,
+ 0x3846e000,
+ 0x38470000,
+ 0x38472000,
+ 0x38474000,
+ 0x38476000,
+ 0x38478000,
+ 0x3847a000,
+ 0x3847c000,
+ 0x3847e000,
+ 0x38480000,
+ 0x38482000,
+ 0x38484000,
+ 0x38486000,
+ 0x38488000,
+ 0x3848a000,
+ 0x3848c000,
+ 0x3848e000,
+ 0x38490000,
+ 0x38492000,
+ 0x38494000,
+ 0x38496000,
+ 0x38498000,
+ 0x3849a000,
+ 0x3849c000,
+ 0x3849e000,
+ 0x384a0000,
+ 0x384a2000,
+ 0x384a4000,
+ 0x384a6000,
+ 0x384a8000,
+ 0x384aa000,
+ 0x384ac000,
+ 0x384ae000,
+ 0x384b0000,
+ 0x384b2000,
+ 0x384b4000,
+ 0x384b6000,
+ 0x384b8000,
+ 0x384ba000,
+ 0x384bc000,
+ 0x384be000,
+ 0x384c0000,
+ 0x384c2000,
+ 0x384c4000,
+ 0x384c6000,
+ 0x384c8000,
+ 0x384ca000,
+ 0x384cc000,
+ 0x384ce000,
+ 0x384d0000,
+ 0x384d2000,
+ 0x384d4000,
+ 0x384d6000,
+ 0x384d8000,
+ 0x384da000,
+ 0x384dc000,
+ 0x384de000,
+ 0x384e0000,
+ 0x384e2000,
+ 0x384e4000,
+ 0x384e6000,
+ 0x384e8000,
+ 0x384ea000,
+ 0x384ec000,
+ 0x384ee000,
+ 0x384f0000,
+ 0x384f2000,
+ 0x384f4000,
+ 0x384f6000,
+ 0x384f8000,
+ 0x384fa000,
+ 0x384fc000,
+ 0x384fe000,
+ 0x38500000,
+ 0x38502000,
+ 0x38504000,
+ 0x38506000,
+ 0x38508000,
+ 0x3850a000,
+ 0x3850c000,
+ 0x3850e000,
+ 0x38510000,
+ 0x38512000,
+ 0x38514000,
+ 0x38516000,
+ 0x38518000,
+ 0x3851a000,
+ 0x3851c000,
+ 0x3851e000,
+ 0x38520000,
+ 0x38522000,
+ 0x38524000,
+ 0x38526000,
+ 0x38528000,
+ 0x3852a000,
+ 0x3852c000,
+ 0x3852e000,
+ 0x38530000,
+ 0x38532000,
+ 0x38534000,
+ 0x38536000,
+ 0x38538000,
+ 0x3853a000,
+ 0x3853c000,
+ 0x3853e000,
+ 0x38540000,
+ 0x38542000,
+ 0x38544000,
+ 0x38546000,
+ 0x38548000,
+ 0x3854a000,
+ 0x3854c000,
+ 0x3854e000,
+ 0x38550000,
+ 0x38552000,
+ 0x38554000,
+ 0x38556000,
+ 0x38558000,
+ 0x3855a000,
+ 0x3855c000,
+ 0x3855e000,
+ 0x38560000,
+ 0x38562000,
+ 0x38564000,
+ 0x38566000,
+ 0x38568000,
+ 0x3856a000,
+ 0x3856c000,
+ 0x3856e000,
+ 0x38570000,
+ 0x38572000,
+ 0x38574000,
+ 0x38576000,
+ 0x38578000,
+ 0x3857a000,
+ 0x3857c000,
+ 0x3857e000,
+ 0x38580000,
+ 0x38582000,
+ 0x38584000,
+ 0x38586000,
+ 0x38588000,
+ 0x3858a000,
+ 0x3858c000,
+ 0x3858e000,
+ 0x38590000,
+ 0x38592000,
+ 0x38594000,
+ 0x38596000,
+ 0x38598000,
+ 0x3859a000,
+ 0x3859c000,
+ 0x3859e000,
+ 0x385a0000,
+ 0x385a2000,
+ 0x385a4000,
+ 0x385a6000,
+ 0x385a8000,
+ 0x385aa000,
+ 0x385ac000,
+ 0x385ae000,
+ 0x385b0000,
+ 0x385b2000,
+ 0x385b4000,
+ 0x385b6000,
+ 0x385b8000,
+ 0x385ba000,
+ 0x385bc000,
+ 0x385be000,
+ 0x385c0000,
+ 0x385c2000,
+ 0x385c4000,
+ 0x385c6000,
+ 0x385c8000,
+ 0x385ca000,
+ 0x385cc000,
+ 0x385ce000,
+ 0x385d0000,
+ 0x385d2000,
+ 0x385d4000,
+ 0x385d6000,
+ 0x385d8000,
+ 0x385da000,
+ 0x385dc000,
+ 0x385de000,
+ 0x385e0000,
+ 0x385e2000,
+ 0x385e4000,
+ 0x385e6000,
+ 0x385e8000,
+ 0x385ea000,
+ 0x385ec000,
+ 0x385ee000,
+ 0x385f0000,
+ 0x385f2000,
+ 0x385f4000,
+ 0x385f6000,
+ 0x385f8000,
+ 0x385fa000,
+ 0x385fc000,
+ 0x385fe000,
+ 0x38600000,
+ 0x38602000,
+ 0x38604000,
+ 0x38606000,
+ 0x38608000,
+ 0x3860a000,
+ 0x3860c000,
+ 0x3860e000,
+ 0x38610000,
+ 0x38612000,
+ 0x38614000,
+ 0x38616000,
+ 0x38618000,
+ 0x3861a000,
+ 0x3861c000,
+ 0x3861e000,
+ 0x38620000,
+ 0x38622000,
+ 0x38624000,
+ 0x38626000,
+ 0x38628000,
+ 0x3862a000,
+ 0x3862c000,
+ 0x3862e000,
+ 0x38630000,
+ 0x38632000,
+ 0x38634000,
+ 0x38636000,
+ 0x38638000,
+ 0x3863a000,
+ 0x3863c000,
+ 0x3863e000,
+ 0x38640000,
+ 0x38642000,
+ 0x38644000,
+ 0x38646000,
+ 0x38648000,
+ 0x3864a000,
+ 0x3864c000,
+ 0x3864e000,
+ 0x38650000,
+ 0x38652000,
+ 0x38654000,
+ 0x38656000,
+ 0x38658000,
+ 0x3865a000,
+ 0x3865c000,
+ 0x3865e000,
+ 0x38660000,
+ 0x38662000,
+ 0x38664000,
+ 0x38666000,
+ 0x38668000,
+ 0x3866a000,
+ 0x3866c000,
+ 0x3866e000,
+ 0x38670000,
+ 0x38672000,
+ 0x38674000,
+ 0x38676000,
+ 0x38678000,
+ 0x3867a000,
+ 0x3867c000,
+ 0x3867e000,
+ 0x38680000,
+ 0x38682000,
+ 0x38684000,
+ 0x38686000,
+ 0x38688000,
+ 0x3868a000,
+ 0x3868c000,
+ 0x3868e000,
+ 0x38690000,
+ 0x38692000,
+ 0x38694000,
+ 0x38696000,
+ 0x38698000,
+ 0x3869a000,
+ 0x3869c000,
+ 0x3869e000,
+ 0x386a0000,
+ 0x386a2000,
+ 0x386a4000,
+ 0x386a6000,
+ 0x386a8000,
+ 0x386aa000,
+ 0x386ac000,
+ 0x386ae000,
+ 0x386b0000,
+ 0x386b2000,
+ 0x386b4000,
+ 0x386b6000,
+ 0x386b8000,
+ 0x386ba000,
+ 0x386bc000,
+ 0x386be000,
+ 0x386c0000,
+ 0x386c2000,
+ 0x386c4000,
+ 0x386c6000,
+ 0x386c8000,
+ 0x386ca000,
+ 0x386cc000,
+ 0x386ce000,
+ 0x386d0000,
+ 0x386d2000,
+ 0x386d4000,
+ 0x386d6000,
+ 0x386d8000,
+ 0x386da000,
+ 0x386dc000,
+ 0x386de000,
+ 0x386e0000,
+ 0x386e2000,
+ 0x386e4000,
+ 0x386e6000,
+ 0x386e8000,
+ 0x386ea000,
+ 0x386ec000,
+ 0x386ee000,
+ 0x386f0000,
+ 0x386f2000,
+ 0x386f4000,
+ 0x386f6000,
+ 0x386f8000,
+ 0x386fa000,
+ 0x386fc000,
+ 0x386fe000,
+ 0x38700000,
+ 0x38702000,
+ 0x38704000,
+ 0x38706000,
+ 0x38708000,
+ 0x3870a000,
+ 0x3870c000,
+ 0x3870e000,
+ 0x38710000,
+ 0x38712000,
+ 0x38714000,
+ 0x38716000,
+ 0x38718000,
+ 0x3871a000,
+ 0x3871c000,
+ 0x3871e000,
+ 0x38720000,
+ 0x38722000,
+ 0x38724000,
+ 0x38726000,
+ 0x38728000,
+ 0x3872a000,
+ 0x3872c000,
+ 0x3872e000,
+ 0x38730000,
+ 0x38732000,
+ 0x38734000,
+ 0x38736000,
+ 0x38738000,
+ 0x3873a000,
+ 0x3873c000,
+ 0x3873e000,
+ 0x38740000,
+ 0x38742000,
+ 0x38744000,
+ 0x38746000,
+ 0x38748000,
+ 0x3874a000,
+ 0x3874c000,
+ 0x3874e000,
+ 0x38750000,
+ 0x38752000,
+ 0x38754000,
+ 0x38756000,
+ 0x38758000,
+ 0x3875a000,
+ 0x3875c000,
+ 0x3875e000,
+ 0x38760000,
+ 0x38762000,
+ 0x38764000,
+ 0x38766000,
+ 0x38768000,
+ 0x3876a000,
+ 0x3876c000,
+ 0x3876e000,
+ 0x38770000,
+ 0x38772000,
+ 0x38774000,
+ 0x38776000,
+ 0x38778000,
+ 0x3877a000,
+ 0x3877c000,
+ 0x3877e000,
+ 0x38780000,
+ 0x38782000,
+ 0x38784000,
+ 0x38786000,
+ 0x38788000,
+ 0x3878a000,
+ 0x3878c000,
+ 0x3878e000,
+ 0x38790000,
+ 0x38792000,
+ 0x38794000,
+ 0x38796000,
+ 0x38798000,
+ 0x3879a000,
+ 0x3879c000,
+ 0x3879e000,
+ 0x387a0000,
+ 0x387a2000,
+ 0x387a4000,
+ 0x387a6000,
+ 0x387a8000,
+ 0x387aa000,
+ 0x387ac000,
+ 0x387ae000,
+ 0x387b0000,
+ 0x387b2000,
+ 0x387b4000,
+ 0x387b6000,
+ 0x387b8000,
+ 0x387ba000,
+ 0x387bc000,
+ 0x387be000,
+ 0x387c0000,
+ 0x387c2000,
+ 0x387c4000,
+ 0x387c6000,
+ 0x387c8000,
+ 0x387ca000,
+ 0x387cc000,
+ 0x387ce000,
+ 0x387d0000,
+ 0x387d2000,
+ 0x387d4000,
+ 0x387d6000,
+ 0x387d8000,
+ 0x387da000,
+ 0x387dc000,
+ 0x387de000,
+ 0x387e0000,
+ 0x387e2000,
+ 0x387e4000,
+ 0x387e6000,
+ 0x387e8000,
+ 0x387ea000,
+ 0x387ec000,
+ 0x387ee000,
+ 0x387f0000,
+ 0x387f2000,
+ 0x387f4000,
+ 0x387f6000,
+ 0x387f8000,
+ 0x387fa000,
+ 0x387fc000,
+ 0x387fe000,
+};
+
+const static unsigned g_exponent[64] = {
+ 0x00000000,
+ 0x00800000,
+ 0x01000000,
+ 0x01800000,
+ 0x02000000,
+ 0x02800000,
+ 0x03000000,
+ 0x03800000,
+ 0x04000000,
+ 0x04800000,
+ 0x05000000,
+ 0x05800000,
+ 0x06000000,
+ 0x06800000,
+ 0x07000000,
+ 0x07800000,
+ 0x08000000,
+ 0x08800000,
+ 0x09000000,
+ 0x09800000,
+ 0x0a000000,
+ 0x0a800000,
+ 0x0b000000,
+ 0x0b800000,
+ 0x0c000000,
+ 0x0c800000,
+ 0x0d000000,
+ 0x0d800000,
+ 0x0e000000,
+ 0x0e800000,
+ 0x0f000000,
+ 0x47800000,
+ 0x80000000,
+ 0x80800000,
+ 0x81000000,
+ 0x81800000,
+ 0x82000000,
+ 0x82800000,
+ 0x83000000,
+ 0x83800000,
+ 0x84000000,
+ 0x84800000,
+ 0x85000000,
+ 0x85800000,
+ 0x86000000,
+ 0x86800000,
+ 0x87000000,
+ 0x87800000,
+ 0x88000000,
+ 0x88800000,
+ 0x89000000,
+ 0x89800000,
+ 0x8a000000,
+ 0x8a800000,
+ 0x8b000000,
+ 0x8b800000,
+ 0x8c000000,
+ 0x8c800000,
+ 0x8d000000,
+ 0x8d800000,
+ 0x8e000000,
+ 0x8e800000,
+ 0x8f000000,
+ 0xc7800000,
+};
+
+const static unsigned g_offset[64] = {
+ 0x00000000,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000000,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+ 0x00000400,
+};
+
+float float16ToFloat32(unsigned short h)
+{
+ unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10];
+ return *(float*) &i32;
+}
+}
+
diff --git a/src/libGLESv2/Float16ToFloat32.py b/src/libGLESv2/Float16ToFloat32.py
new file mode 100644
index 00000000..cf039bfc
--- /dev/null
+++ b/src/libGLESv2/Float16ToFloat32.py
@@ -0,0 +1,78 @@
+# Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+
+# This script generates a function that converts 16-bit precision floating
+# point numbers to 32-bit.
+# It is based on ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf.
+
+def convertMantissa(i):
+ if i == 0:
+ return 0
+ elif i < 1024:
+ m = i << 13
+ e = 0
+ while not (m & 0x00800000):
+ e -= 0x00800000
+ m = m << 1
+ m &= ~0x00800000
+ e += 0x38800000
+ return m | e
+ else:
+ return 0x38000000 + ((i - 1024) << 13)
+
+def convertExponent(i):
+ if i == 0:
+ return 0
+ elif i in range(1, 31):
+ return i << 23
+ elif i == 31:
+ return 0x47800000
+ elif i == 32:
+ return 0x80000000
+ elif i in range(33, 63):
+ return 0x80000000 + ((i - 32) << 23)
+ else:
+ return 0xC7800000
+
+def convertOffset(i):
+ if i == 0 or i == 32:
+ return 0
+ else:
+ return 1024
+
+print """//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is automatically generated.
+
+namespace gl
+{
+"""
+
+print "const static unsigned g_mantissa[2048] = {"
+for i in range(0, 2048):
+ print " %#010x," % convertMantissa(i)
+print "};\n"
+
+print "const static unsigned g_exponent[64] = {"
+for i in range(0, 64):
+ print " %#010x," % convertExponent(i)
+print "};\n"
+
+print "const static unsigned g_offset[64] = {"
+for i in range(0, 64):
+ print " %#010x," % convertOffset(i)
+print "};\n"
+
+print """float float16ToFloat32(unsigned short h)
+{
+ unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10];
+ return *(float*) &i32;
+}
+}
+"""
diff --git a/src/libGLESv2/Framebuffer.cpp b/src/libGLESv2/Framebuffer.cpp
new file mode 100644
index 00000000..b0abba0a
--- /dev/null
+++ b/src/libGLESv2/Framebuffer.cpp
@@ -0,0 +1,603 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
+
+#include "libGLESv2/Framebuffer.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/Renderbuffer.h"
+
+namespace gl
+{
+
+Framebuffer::Framebuffer(rx::Renderer *renderer)
+ : mRenderer(renderer)
+{
+ for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ mColorbufferTypes[colorAttachment] = GL_NONE;
+ mDrawBufferStates[colorAttachment] = GL_NONE;
+ }
+ mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT;
+ mReadBufferState = GL_COLOR_ATTACHMENT0_EXT;
+
+ mDepthbufferType = GL_NONE;
+ mStencilbufferType = GL_NONE;
+}
+
+Framebuffer::~Framebuffer()
+{
+ for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ mColorbufferPointers[colorAttachment].set(NULL);
+ }
+ mDepthbufferPointer.set(NULL);
+ mStencilbufferPointer.set(NULL);
+}
+
+Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
+{
+ gl::Context *context = gl::getContext();
+ Renderbuffer *buffer = NULL;
+
+ if (type == GL_NONE)
+ {
+ buffer = NULL;
+ }
+ else if (type == GL_RENDERBUFFER)
+ {
+ buffer = context->getRenderbuffer(handle);
+ }
+ else if (IsInternalTextureTarget(type))
+ {
+ buffer = context->getTexture(handle)->getRenderbuffer(type);
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+
+ return buffer;
+}
+
+void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer)
+{
+ ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
+ mColorbufferTypes[colorAttachment] = (colorbuffer != 0) ? type : GL_NONE;
+ mColorbufferPointers[colorAttachment].set(lookupRenderbuffer(type, colorbuffer));
+}
+
+void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
+{
+ mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE;
+ mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
+}
+
+void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
+{
+ mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE;
+ mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
+}
+
+void Framebuffer::detachTexture(GLuint texture)
+{
+ for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (mColorbufferPointers[colorAttachment].id() == texture && IsInternalTextureTarget(mColorbufferTypes[colorAttachment]))
+ {
+ mColorbufferTypes[colorAttachment] = GL_NONE;
+ mColorbufferPointers[colorAttachment].set(NULL);
+ }
+ }
+
+ if (mDepthbufferPointer.id() == texture && IsInternalTextureTarget(mDepthbufferType))
+ {
+ mDepthbufferType = GL_NONE;
+ mDepthbufferPointer.set(NULL);
+ }
+
+ if (mStencilbufferPointer.id() == texture && IsInternalTextureTarget(mStencilbufferType))
+ {
+ mStencilbufferType = GL_NONE;
+ mStencilbufferPointer.set(NULL);
+ }
+}
+
+void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
+{
+ for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (mColorbufferPointers[colorAttachment].id() == renderbuffer && mColorbufferTypes[colorAttachment] == GL_RENDERBUFFER)
+ {
+ mColorbufferTypes[colorAttachment] = GL_NONE;
+ mColorbufferPointers[colorAttachment].set(NULL);
+ }
+ }
+
+ if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
+ {
+ mDepthbufferType = GL_NONE;
+ mDepthbufferPointer.set(NULL);
+ }
+
+ if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
+ {
+ mStencilbufferType = GL_NONE;
+ mStencilbufferPointer.set(NULL);
+ }
+}
+
+unsigned int Framebuffer::getRenderTargetSerial(unsigned int colorAttachment) const
+{
+ ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
+
+ Renderbuffer *colorbuffer = mColorbufferPointers[colorAttachment].get();
+
+ if (colorbuffer)
+ {
+ return colorbuffer->getSerial();
+ }
+
+ return 0;
+}
+
+unsigned int Framebuffer::getDepthbufferSerial() const
+{
+ Renderbuffer *depthbuffer = mDepthbufferPointer.get();
+
+ if (depthbuffer)
+ {
+ return depthbuffer->getSerial();
+ }
+
+ return 0;
+}
+
+unsigned int Framebuffer::getStencilbufferSerial() const
+{
+ Renderbuffer *stencilbuffer = mStencilbufferPointer.get();
+
+ if (stencilbuffer)
+ {
+ return stencilbuffer->getSerial();
+ }
+
+ return 0;
+}
+
+Renderbuffer *Framebuffer::getColorbuffer(unsigned int colorAttachment) const
+{
+ ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
+ return mColorbufferPointers[colorAttachment].get();
+}
+
+Renderbuffer *Framebuffer::getDepthbuffer() const
+{
+ return mDepthbufferPointer.get();
+}
+
+Renderbuffer *Framebuffer::getStencilbuffer() const
+{
+ return mStencilbufferPointer.get();
+}
+
+Renderbuffer *Framebuffer::getDepthOrStencilbuffer() const
+{
+ Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
+
+ if (!depthstencilbuffer)
+ {
+ depthstencilbuffer = mStencilbufferPointer.get();
+ }
+
+ return depthstencilbuffer;
+}
+
+Renderbuffer *Framebuffer::getReadColorbuffer() const
+{
+ // Will require more logic if glReadBuffers is supported
+ return mColorbufferPointers[0].get();
+}
+
+GLenum Framebuffer::getReadColorbufferType() const
+{
+ // Will require more logic if glReadBuffers is supported
+ return mColorbufferTypes[0];
+}
+
+Renderbuffer *Framebuffer::getFirstColorbuffer() const
+{
+ for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (mColorbufferTypes[colorAttachment] != GL_NONE)
+ {
+ return mColorbufferPointers[colorAttachment].get();
+ }
+ }
+
+ return NULL;
+}
+
+GLenum Framebuffer::getColorbufferType(unsigned int colorAttachment) const
+{
+ ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
+ return mColorbufferTypes[colorAttachment];
+}
+
+GLenum Framebuffer::getDepthbufferType() const
+{
+ return mDepthbufferType;
+}
+
+GLenum Framebuffer::getStencilbufferType() const
+{
+ return mStencilbufferType;
+}
+
+GLuint Framebuffer::getColorbufferHandle(unsigned int colorAttachment) const
+{
+ ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS);
+ return mColorbufferPointers[colorAttachment].id();
+}
+
+GLuint Framebuffer::getDepthbufferHandle() const
+{
+ return mDepthbufferPointer.id();
+}
+
+GLuint Framebuffer::getStencilbufferHandle() const
+{
+ return mStencilbufferPointer.id();
+}
+
+GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const
+{
+ return mDrawBufferStates[colorAttachment];
+}
+
+void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer)
+{
+ mDrawBufferStates[colorAttachment] = drawBuffer;
+}
+
+bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const
+{
+ return (mColorbufferTypes[colorAttachment] != GL_NONE && mDrawBufferStates[colorAttachment] != GL_NONE);
+}
+
+bool Framebuffer::hasEnabledColorAttachment() const
+{
+ for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (isEnabledColorAttachment(colorAttachment))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Framebuffer::hasStencil() const
+{
+ if (mStencilbufferType != GL_NONE)
+ {
+ const Renderbuffer *stencilbufferObject = getStencilbuffer();
+
+ if (stencilbufferObject)
+ {
+ return stencilbufferObject->getStencilSize() > 0;
+ }
+ }
+
+ return false;
+}
+
+bool Framebuffer::usingExtendedDrawBuffers() const
+{
+ for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (isEnabledColorAttachment(colorAttachment))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+GLenum Framebuffer::completeness() const
+{
+ int width = 0;
+ int height = 0;
+ int colorbufferSize = 0;
+ int samples = -1;
+ bool missingAttachment = true;
+
+ for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (mColorbufferTypes[colorAttachment] != GL_NONE)
+ {
+ const Renderbuffer *colorbuffer = getColorbuffer(colorAttachment);
+
+ if (!colorbuffer)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (mColorbufferTypes[colorAttachment] == GL_RENDERBUFFER)
+ {
+ if (!gl::IsColorRenderable(colorbuffer->getInternalFormat()))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if (IsInternalTextureTarget(mColorbufferTypes[colorAttachment]))
+ {
+ GLint internalformat = colorbuffer->getInternalFormat();
+ GLenum format = gl::ExtractFormat(internalformat);
+
+ if (IsCompressed(format) ||
+ format == GL_ALPHA ||
+ format == GL_LUMINANCE ||
+ format == GL_LUMINANCE_ALPHA)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ bool filtering, renderable;
+
+ if ((gl::IsFloat32Format(internalformat) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
+ (gl::IsFloat16Format(internalformat) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ if (gl::IsDepthTexture(internalformat) || gl::IsStencilTexture(internalformat))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (!missingAttachment)
+ {
+ // all color attachments must have the same width and height
+ if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ }
+
+ // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
+ // all color attachments have the same number of samples for the FBO to be complete.
+ if (colorbuffer->getSamples() != samples)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
+ }
+
+ // all color attachments attachments must have the same number of bitplanes
+ if (gl::ComputePixelSize(colorbuffer->getInternalFormat()) != colorbufferSize)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness
+ for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++)
+ {
+ if (mColorbufferPointers[colorAttachment].get() == mColorbufferPointers[previousColorAttachment].get())
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+ }
+ }
+ else
+ {
+ width = colorbuffer->getWidth();
+ height = colorbuffer->getHeight();
+ samples = colorbuffer->getSamples();
+ colorbufferSize = gl::ComputePixelSize(colorbuffer->getInternalFormat());
+ missingAttachment = false;
+ }
+ }
+ }
+
+ const Renderbuffer *depthbuffer = NULL;
+ const Renderbuffer *stencilbuffer = NULL;
+
+ if (mDepthbufferType != GL_NONE)
+ {
+ depthbuffer = getDepthbuffer();
+
+ if (!depthbuffer)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (mDepthbufferType == GL_RENDERBUFFER)
+ {
+ if (!gl::IsDepthRenderable(depthbuffer->getInternalFormat()))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if (IsInternalTextureTarget(mDepthbufferType))
+ {
+ GLint internalformat = depthbuffer->getInternalFormat();
+
+ // depth texture attachments require OES/ANGLE_depth_texture
+ if (!mRenderer->getDepthTextureSupport())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (!gl::IsDepthTexture(internalformat))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (missingAttachment)
+ {
+ width = depthbuffer->getWidth();
+ height = depthbuffer->getHeight();
+ samples = depthbuffer->getSamples();
+ missingAttachment = false;
+ }
+ else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ }
+ else if (samples != depthbuffer->getSamples())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+ }
+ }
+
+ if (mStencilbufferType != GL_NONE)
+ {
+ stencilbuffer = getStencilbuffer();
+
+ if (!stencilbuffer)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (mStencilbufferType == GL_RENDERBUFFER)
+ {
+ if (!gl::IsStencilRenderable(stencilbuffer->getInternalFormat()))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if (IsInternalTextureTarget(mStencilbufferType))
+ {
+ GLint internalformat = stencilbuffer->getInternalFormat();
+
+ // texture stencil attachments come along as part
+ // of OES_packed_depth_stencil + OES/ANGLE_depth_texture
+ if (!mRenderer->getDepthTextureSupport())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (!gl::IsStencilTexture(internalformat))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (missingAttachment)
+ {
+ width = stencilbuffer->getWidth();
+ height = stencilbuffer->getHeight();
+ samples = stencilbuffer->getSamples();
+ missingAttachment = false;
+ }
+ else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ }
+ else if (samples != stencilbuffer->getSamples())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+ }
+ }
+
+ // if we have both a depth and stencil buffer, they must refer to the same object
+ // since we only support packed_depth_stencil and not separate depth and stencil
+ if (depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer))
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ // we need to have at least one attachment to be complete
+ if (missingAttachment)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ }
+
+ return GL_FRAMEBUFFER_COMPLETE;
+}
+
+DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
+ : Framebuffer(renderer)
+{
+ mColorbufferPointers[0].set(new Renderbuffer(mRenderer, 0, colorbuffer));
+
+ Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(mRenderer, 0, depthStencil);
+ mDepthbufferPointer.set(depthStencilRenderbuffer);
+ mStencilbufferPointer.set(depthStencilRenderbuffer);
+
+ mColorbufferTypes[0] = GL_RENDERBUFFER;
+ mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
+ mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
+
+ mDrawBufferStates[0] = GL_BACK;
+ mReadBufferState = GL_BACK;
+}
+
+int Framebuffer::getSamples() const
+{
+ if (completeness() == GL_FRAMEBUFFER_COMPLETE)
+ {
+ // for a complete framebuffer, all attachments must have the same sample count
+ // in this case return the first nonzero sample size
+ for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (mColorbufferTypes[colorAttachment] != GL_NONE)
+ {
+ return getColorbuffer(colorAttachment)->getSamples();
+ }
+ }
+ }
+
+ return 0;
+}
+
+GLenum DefaultFramebuffer::completeness() const
+{
+ // The default framebuffer *must* always be complete, though it may not be
+ // subject to the same rules as application FBOs. ie, it could have 0x0 size.
+ return GL_FRAMEBUFFER_COMPLETE;
+}
+
+}
diff --git a/src/libGLESv2/Framebuffer.h b/src/libGLESv2/Framebuffer.h
new file mode 100644
index 00000000..b54e008d
--- /dev/null
+++ b/src/libGLESv2/Framebuffer.h
@@ -0,0 +1,108 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Framebuffer.h: Defines the gl::Framebuffer class. Implements GL framebuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
+
+#ifndef LIBGLESV2_FRAMEBUFFER_H_
+#define LIBGLESV2_FRAMEBUFFER_H_
+
+#include "common/angleutils.h"
+#include "common/RefCountObject.h"
+#include "constants.h"
+
+namespace rx
+{
+class Renderer;
+}
+
+namespace gl
+{
+class Renderbuffer;
+class Colorbuffer;
+class Depthbuffer;
+class Stencilbuffer;
+class DepthStencilbuffer;
+
+class Framebuffer
+{
+ public:
+ explicit Framebuffer(rx::Renderer *renderer);
+
+ virtual ~Framebuffer();
+
+ void setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer);
+ void setDepthbuffer(GLenum type, GLuint depthbuffer);
+ void setStencilbuffer(GLenum type, GLuint stencilbuffer);
+
+ void detachTexture(GLuint texture);
+ void detachRenderbuffer(GLuint renderbuffer);
+
+ unsigned int getRenderTargetSerial(unsigned int colorAttachment) const;
+ unsigned int getDepthbufferSerial() const;
+ unsigned int getStencilbufferSerial() const;
+
+ Renderbuffer *getColorbuffer(unsigned int colorAttachment) const;
+ Renderbuffer *getDepthbuffer() const;
+ Renderbuffer *getStencilbuffer() const;
+ Renderbuffer *getDepthOrStencilbuffer() const;
+ Renderbuffer *getReadColorbuffer() const;
+ GLenum getReadColorbufferType() const;
+ Renderbuffer *getFirstColorbuffer() const;
+
+ GLenum getColorbufferType(unsigned int colorAttachment) const;
+ GLenum getDepthbufferType() const;
+ GLenum getStencilbufferType() const;
+
+ GLuint getColorbufferHandle(unsigned int colorAttachment) const;
+ GLuint getDepthbufferHandle() const;
+ GLuint getStencilbufferHandle() const;
+
+ GLenum getDrawBufferState(unsigned int colorAttachment) const;
+ void setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer);
+
+ bool isEnabledColorAttachment(unsigned int colorAttachment) const;
+ bool hasEnabledColorAttachment() const;
+ bool hasStencil() const;
+ int getSamples() const;
+ bool usingExtendedDrawBuffers() const;
+
+ virtual GLenum completeness() const;
+
+ protected:
+ GLenum mColorbufferTypes[IMPLEMENTATION_MAX_DRAW_BUFFERS];
+ BindingPointer<Renderbuffer> mColorbufferPointers[IMPLEMENTATION_MAX_DRAW_BUFFERS];
+ GLenum mDrawBufferStates[IMPLEMENTATION_MAX_DRAW_BUFFERS];
+ GLenum mReadBufferState;
+
+ GLenum mDepthbufferType;
+ BindingPointer<Renderbuffer> mDepthbufferPointer;
+
+ GLenum mStencilbufferType;
+ BindingPointer<Renderbuffer> mStencilbufferPointer;
+
+ rx::Renderer *mRenderer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Framebuffer);
+
+ Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle) const;
+};
+
+class DefaultFramebuffer : public Framebuffer
+{
+ public:
+ DefaultFramebuffer(rx::Renderer *Renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil);
+
+ virtual GLenum completeness() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DefaultFramebuffer);
+};
+
+}
+
+#endif // LIBGLESV2_FRAMEBUFFER_H_
diff --git a/src/libGLESv2/HandleAllocator.cpp b/src/libGLESv2/HandleAllocator.cpp
new file mode 100644
index 00000000..37da99aa
--- /dev/null
+++ b/src/libGLESv2/HandleAllocator.cpp
@@ -0,0 +1,64 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// HandleAllocator.cpp: Implements the gl::HandleAllocator class, which is used
+// to allocate GL handles.
+
+#include "libGLESv2/HandleAllocator.h"
+
+#include "libGLESv2/main.h"
+
+namespace gl
+{
+
+HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1)
+{
+}
+
+HandleAllocator::~HandleAllocator()
+{
+}
+
+void HandleAllocator::setBaseHandle(GLuint value)
+{
+ ASSERT(mBaseValue == mNextValue);
+ mBaseValue = value;
+ mNextValue = value;
+}
+
+GLuint HandleAllocator::allocate()
+{
+ if (mFreeValues.size())
+ {
+ GLuint handle = mFreeValues.back();
+ mFreeValues.pop_back();
+ return handle;
+ }
+ return mNextValue++;
+}
+
+void HandleAllocator::release(GLuint handle)
+{
+ if (handle == mNextValue - 1)
+ {
+ // Don't drop below base value
+ if(mNextValue > mBaseValue)
+ {
+ mNextValue--;
+ }
+ }
+ else
+ {
+ // Only free handles that we own - don't drop below the base value
+ if (handle >= mBaseValue)
+ {
+ mFreeValues.push_back(handle);
+ }
+ }
+}
+
+}
diff --git a/src/libGLESv2/HandleAllocator.h b/src/libGLESv2/HandleAllocator.h
new file mode 100644
index 00000000..a92e1684
--- /dev/null
+++ b/src/libGLESv2/HandleAllocator.h
@@ -0,0 +1,45 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// HandleAllocator.h: Defines the gl::HandleAllocator class, which is used to
+// allocate GL handles.
+
+#ifndef LIBGLESV2_HANDLEALLOCATOR_H_
+#define LIBGLESV2_HANDLEALLOCATOR_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <vector>
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+
+class HandleAllocator
+{
+ public:
+ HandleAllocator();
+ virtual ~HandleAllocator();
+
+ void setBaseHandle(GLuint value);
+
+ GLuint allocate();
+ void release(GLuint handle);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HandleAllocator);
+
+ GLuint mBaseValue;
+ GLuint mNextValue;
+ typedef std::vector<GLuint> HandleList;
+ HandleList mFreeValues;
+};
+
+}
+
+#endif // LIBGLESV2_HANDLEALLOCATOR_H_
diff --git a/src/libGLESv2/Program.cpp b/src/libGLESv2/Program.cpp
new file mode 100644
index 00000000..c38aa5a6
--- /dev/null
+++ b/src/libGLESv2/Program.cpp
@@ -0,0 +1,525 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// Program.cpp: Implements the gl::Program class. Implements GL program objects
+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
+
+#include "libGLESv2/Program.h"
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/ResourceManager.h"
+
+namespace gl
+{
+const char * const g_fakepath = "C:\\fakepath";
+
+AttributeBindings::AttributeBindings()
+{
+}
+
+AttributeBindings::~AttributeBindings()
+{
+}
+
+InfoLog::InfoLog() : mInfoLog(NULL)
+{
+}
+
+InfoLog::~InfoLog()
+{
+ delete[] mInfoLog;
+}
+
+
+int InfoLog::getLength() const
+{
+ if (!mInfoLog)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(mInfoLog) + 1;
+ }
+}
+
+void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+ int index = 0;
+
+ if (bufSize > 0)
+ {
+ if (mInfoLog)
+ {
+ index = std::min(bufSize - 1, (int)strlen(mInfoLog));
+ memcpy(infoLog, mInfoLog, index);
+ }
+
+ infoLog[index] = '\0';
+ }
+
+ if (length)
+ {
+ *length = index;
+ }
+}
+
+// append a santized message to the program info log.
+// The D3D compiler includes a fake file path in some of the warning or error
+// messages, so lets remove all occurrences of this fake file path from the log.
+void InfoLog::appendSanitized(const char *message)
+{
+ std::string msg(message);
+
+ size_t found;
+ do
+ {
+ found = msg.find(g_fakepath);
+ if (found != std::string::npos)
+ {
+ msg.erase(found, strlen(g_fakepath));
+ }
+ }
+ while (found != std::string::npos);
+
+ append("%s", msg.c_str());
+}
+
+void InfoLog::append(const char *format, ...)
+{
+ if (!format)
+ {
+ return;
+ }
+
+ char info[1024];
+
+ va_list vararg;
+ va_start(vararg, format);
+ vsnprintf(info, sizeof(info), format, vararg);
+ va_end(vararg);
+
+ size_t infoLength = strlen(info);
+
+ if (!mInfoLog)
+ {
+ mInfoLog = new char[infoLength + 2];
+ strcpy(mInfoLog, info);
+ strcpy(mInfoLog + infoLength, "\n");
+ }
+ else
+ {
+ size_t logLength = strlen(mInfoLog);
+ char *newLog = new char[logLength + infoLength + 2];
+ strcpy(newLog, mInfoLog);
+ strcpy(newLog + logLength, info);
+ strcpy(newLog + logLength + infoLength, "\n");
+
+ delete[] mInfoLog;
+ mInfoLog = newLog;
+ }
+}
+
+void InfoLog::reset()
+{
+ if (mInfoLog)
+ {
+ delete [] mInfoLog;
+ mInfoLog = NULL;
+ }
+}
+
+Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
+{
+ mFragmentShader = NULL;
+ mVertexShader = NULL;
+ mProgramBinary.set(NULL);
+ mDeleteStatus = false;
+ mLinked = false;
+ mRefCount = 0;
+ mRenderer = renderer;
+}
+
+Program::~Program()
+{
+ unlink(true);
+
+ if (mVertexShader != NULL)
+ {
+ mVertexShader->release();
+ }
+
+ if (mFragmentShader != NULL)
+ {
+ mFragmentShader->release();
+ }
+}
+
+bool Program::attachShader(Shader *shader)
+{
+ if (shader->getType() == GL_VERTEX_SHADER)
+ {
+ if (mVertexShader)
+ {
+ return false;
+ }
+
+ mVertexShader = (VertexShader*)shader;
+ mVertexShader->addRef();
+ }
+ else if (shader->getType() == GL_FRAGMENT_SHADER)
+ {
+ if (mFragmentShader)
+ {
+ return false;
+ }
+
+ mFragmentShader = (FragmentShader*)shader;
+ mFragmentShader->addRef();
+ }
+ else UNREACHABLE();
+
+ return true;
+}
+
+bool Program::detachShader(Shader *shader)
+{
+ if (shader->getType() == GL_VERTEX_SHADER)
+ {
+ if (mVertexShader != shader)
+ {
+ return false;
+ }
+
+ mVertexShader->release();
+ mVertexShader = NULL;
+ }
+ else if (shader->getType() == GL_FRAGMENT_SHADER)
+ {
+ if (mFragmentShader != shader)
+ {
+ return false;
+ }
+
+ mFragmentShader->release();
+ mFragmentShader = NULL;
+ }
+ else UNREACHABLE();
+
+ return true;
+}
+
+int Program::getAttachedShadersCount() const
+{
+ return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
+}
+
+void AttributeBindings::bindAttributeLocation(GLuint index, const char *name)
+{
+ if (index < MAX_VERTEX_ATTRIBS)
+ {
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mAttributeBinding[i].erase(name);
+ }
+
+ mAttributeBinding[index].insert(name);
+ }
+}
+
+void Program::bindAttributeLocation(GLuint index, const char *name)
+{
+ mAttributeBindings.bindAttributeLocation(index, name);
+}
+
+// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
+// compiling them into binaries, determining the attribute mappings, and collecting
+// a list of uniforms
+bool Program::link()
+{
+ unlink(false);
+
+ mInfoLog.reset();
+
+ mProgramBinary.set(new ProgramBinary(mRenderer));
+ mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader);
+
+ return mLinked;
+}
+
+int AttributeBindings::getAttributeBinding(const std::string &name) const
+{
+ for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
+ {
+ if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
+ {
+ return location;
+ }
+ }
+
+ return -1;
+}
+
+// Returns the program object to an unlinked state, before re-linking, or at destruction
+void Program::unlink(bool destroy)
+{
+ if (destroy) // Object being destructed
+ {
+ if (mFragmentShader)
+ {
+ mFragmentShader->release();
+ mFragmentShader = NULL;
+ }
+
+ if (mVertexShader)
+ {
+ mVertexShader->release();
+ mVertexShader = NULL;
+ }
+ }
+
+ mProgramBinary.set(NULL);
+ mLinked = false;
+}
+
+bool Program::isLinked()
+{
+ return mLinked;
+}
+
+ProgramBinary* Program::getProgramBinary()
+{
+ return mProgramBinary.get();
+}
+
+bool Program::setProgramBinary(const void *binary, GLsizei length)
+{
+ unlink(false);
+
+ mInfoLog.reset();
+
+ mProgramBinary.set(new ProgramBinary(mRenderer));
+ mLinked = mProgramBinary->load(mInfoLog, binary, length);
+ if (!mLinked)
+ {
+ mProgramBinary.set(NULL);
+ }
+
+ return mLinked;
+}
+
+void Program::release()
+{
+ mRefCount--;
+
+ if (mRefCount == 0 && mDeleteStatus)
+ {
+ mResourceManager->deleteProgram(mHandle);
+ }
+}
+
+void Program::addRef()
+{
+ mRefCount++;
+}
+
+unsigned int Program::getRefCount() const
+{
+ return mRefCount;
+}
+
+GLint Program::getProgramBinaryLength() const
+{
+ ProgramBinary *programBinary = mProgramBinary.get();
+ if (programBinary)
+ {
+ return programBinary->getLength();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int Program::getInfoLogLength() const
+{
+ return mInfoLog.getLength();
+}
+
+void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+ return mInfoLog.getLog(bufSize, length, infoLog);
+}
+
+void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
+{
+ int total = 0;
+
+ if (mVertexShader)
+ {
+ if (total < maxCount)
+ {
+ shaders[total] = mVertexShader->getHandle();
+ }
+
+ total++;
+ }
+
+ if (mFragmentShader)
+ {
+ if (total < maxCount)
+ {
+ shaders[total] = mFragmentShader->getHandle();
+ }
+
+ total++;
+ }
+
+ if (count)
+ {
+ *count = total;
+ }
+}
+
+void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+ ProgramBinary *programBinary = getProgramBinary();
+ if (programBinary)
+ {
+ programBinary->getActiveAttribute(index, bufsize, length, size, type, name);
+ }
+ else
+ {
+ if (bufsize > 0)
+ {
+ name[0] = '\0';
+ }
+
+ if (length)
+ {
+ *length = 0;
+ }
+
+ *type = GL_NONE;
+ *size = 1;
+ }
+}
+
+GLint Program::getActiveAttributeCount()
+{
+ ProgramBinary *programBinary = getProgramBinary();
+ if (programBinary)
+ {
+ return programBinary->getActiveAttributeCount();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+GLint Program::getActiveAttributeMaxLength()
+{
+ ProgramBinary *programBinary = getProgramBinary();
+ if (programBinary)
+ {
+ return programBinary->getActiveAttributeMaxLength();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+ ProgramBinary *programBinary = getProgramBinary();
+ if (programBinary)
+ {
+ return programBinary->getActiveUniform(index, bufsize, length, size, type, name);
+ }
+ else
+ {
+ if (bufsize > 0)
+ {
+ name[0] = '\0';
+ }
+
+ if (length)
+ {
+ *length = 0;
+ }
+
+ *size = 0;
+ *type = GL_NONE;
+ }
+}
+
+GLint Program::getActiveUniformCount()
+{
+ ProgramBinary *programBinary = getProgramBinary();
+ if (programBinary)
+ {
+ return programBinary->getActiveUniformCount();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+GLint Program::getActiveUniformMaxLength()
+{
+ ProgramBinary *programBinary = getProgramBinary();
+ if (programBinary)
+ {
+ return programBinary->getActiveUniformMaxLength();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void Program::flagForDeletion()
+{
+ mDeleteStatus = true;
+}
+
+bool Program::isFlaggedForDeletion() const
+{
+ return mDeleteStatus;
+}
+
+void Program::validate()
+{
+ mInfoLog.reset();
+
+ ProgramBinary *programBinary = getProgramBinary();
+ if (isLinked() && programBinary)
+ {
+ programBinary->validate(mInfoLog);
+ }
+ else
+ {
+ mInfoLog.append("Program has not been successfully linked.");
+ }
+}
+
+bool Program::isValidated() const
+{
+ ProgramBinary *programBinary = mProgramBinary.get();
+ if (programBinary)
+ {
+ return programBinary->isValidated();
+ }
+ else
+ {
+ return false;
+ }
+}
+
+}
diff --git a/src/libGLESv2/Program.h b/src/libGLESv2/Program.h
new file mode 100644
index 00000000..a9db8340
--- /dev/null
+++ b/src/libGLESv2/Program.h
@@ -0,0 +1,130 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Program.h: Defines the gl::Program class. Implements GL program objects
+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
+
+#ifndef LIBGLESV2_PROGRAM_H_
+#define LIBGLESV2_PROGRAM_H_
+
+#include <string>
+#include <set>
+
+#include "common/angleutils.h"
+#include "common/RefCountObject.h"
+#include "libGLESv2/Constants.h"
+
+namespace rx
+{
+class Renderer;
+}
+
+namespace gl
+{
+class ResourceManager;
+class FragmentShader;
+class VertexShader;
+class ProgramBinary;
+class Shader;
+
+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<std::string> mAttributeBinding[MAX_VERTEX_ATTRIBS];
+};
+
+class InfoLog
+{
+ public:
+ InfoLog();
+ ~InfoLog();
+
+ int getLength() const;
+ void getLog(GLsizei bufSize, GLsizei *length, char *infoLog);
+
+ void appendSanitized(const char *message);
+ void append(const char *info, ...);
+ void reset();
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InfoLog);
+ char *mInfoLog;
+};
+
+class Program
+{
+ public:
+ Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle);
+
+ ~Program();
+
+ bool attachShader(Shader *shader);
+ bool detachShader(Shader *shader);
+ int getAttachedShadersCount() const;
+
+ void bindAttributeLocation(GLuint index, const char *name);
+
+ bool link();
+ bool isLinked();
+ bool setProgramBinary(const void *binary, GLsizei length);
+ ProgramBinary *getProgramBinary();
+
+ int getInfoLogLength() const;
+ void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
+ void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
+
+ void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+ GLint getActiveAttributeCount();
+ GLint getActiveAttributeMaxLength();
+
+ void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+ GLint getActiveUniformCount();
+ GLint getActiveUniformMaxLength();
+
+ void addRef();
+ void release();
+ unsigned int getRefCount() const;
+ void flagForDeletion();
+ bool isFlaggedForDeletion() const;
+
+ void validate();
+ bool isValidated() const;
+
+ GLint getProgramBinaryLength() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Program);
+
+ void unlink(bool destroy = false);
+
+ FragmentShader *mFragmentShader;
+ VertexShader *mVertexShader;
+
+ AttributeBindings mAttributeBindings;
+
+ BindingPointer<ProgramBinary> mProgramBinary;
+ bool mLinked;
+ bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use
+
+ unsigned int mRefCount;
+
+ ResourceManager *mResourceManager;
+ rx::Renderer *mRenderer;
+ const GLuint mHandle;
+
+ InfoLog mInfoLog;
+};
+}
+
+#endif // LIBGLESV2_PROGRAM_H_
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
new file mode 100644
index 00000000..135facd8
--- /dev/null
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -0,0 +1,2620 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// Program.cpp: Implements the gl::Program class. Implements GL program objects
+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
+
+#include "libGLESv2/BinaryStream.h"
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/renderer/ShaderExecutable.h"
+
+#include "common/debug.h"
+#include "common/version.h"
+#include "utilities.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/Shader.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/renderer/VertexDataManager.h"
+
+#undef near
+#undef far
+
+namespace gl
+{
+std::string str(int i)
+{
+ char buffer[20];
+ snprintf(buffer, sizeof(buffer), "%d", i);
+ return buffer;
+}
+
+UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
+ : name(name), element(element), index(index)
+{
+}
+
+unsigned int ProgramBinary::mCurrentSerial = 1;
+
+ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
+{
+ mPixelExecutable = NULL;
+ mVertexExecutable = NULL;
+ mGeometryExecutable = NULL;
+
+ mValidated = false;
+
+ for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+ {
+ mSemanticIndex[index] = -1;
+ }
+
+ for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
+ {
+ mSamplersPS[index].active = false;
+ }
+
+ for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
+ {
+ mSamplersVS[index].active = false;
+ }
+
+ mUsedVertexSamplerRange = 0;
+ mUsedPixelSamplerRange = 0;
+ mUsesPointSize = false;
+}
+
+ProgramBinary::~ProgramBinary()
+{
+ delete mPixelExecutable;
+ mPixelExecutable = NULL;
+
+ delete mVertexExecutable;
+ mVertexExecutable = NULL;
+
+ delete mGeometryExecutable;
+ mGeometryExecutable = NULL;
+
+ while (!mUniforms.empty())
+ {
+ delete mUniforms.back();
+ mUniforms.pop_back();
+ }
+}
+
+unsigned int ProgramBinary::getSerial() const
+{
+ return mSerial;
+}
+
+unsigned int ProgramBinary::issueSerial()
+{
+ return mCurrentSerial++;
+}
+
+rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
+{
+ return mPixelExecutable;
+}
+
+rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
+{
+ return mVertexExecutable;
+}
+
+rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
+{
+ return mGeometryExecutable;
+}
+
+GLuint ProgramBinary::getAttributeLocation(const char *name)
+{
+ if (name)
+ {
+ for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+ {
+ if (mLinkedAttribute[index].name == std::string(name))
+ {
+ return index;
+ }
+ }
+ }
+
+ return -1;
+}
+
+int ProgramBinary::getSemanticIndex(int attributeIndex)
+{
+ ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
+
+ return mSemanticIndex[attributeIndex];
+}
+
+// Returns one more than the highest sampler index used.
+GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
+{
+ switch (type)
+ {
+ case SAMPLER_PIXEL:
+ return mUsedPixelSamplerRange;
+ case SAMPLER_VERTEX:
+ return mUsedVertexSamplerRange;
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+bool ProgramBinary::usesPointSize() const
+{
+ return mUsesPointSize;
+}
+
+bool ProgramBinary::usesPointSpriteEmulation() const
+{
+ return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
+}
+
+bool ProgramBinary::usesGeometryShader() const
+{
+ return usesPointSpriteEmulation();
+}
+
+// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
+// index (0-15 for the pixel shader and 0-3 for the vertex shader).
+GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
+{
+ GLint logicalTextureUnit = -1;
+
+ switch (type)
+ {
+ case SAMPLER_PIXEL:
+ ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
+
+ if (mSamplersPS[samplerIndex].active)
+ {
+ logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
+ }
+ break;
+ case SAMPLER_VERTEX:
+ ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
+
+ if (mSamplersVS[samplerIndex].active)
+ {
+ logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
+ {
+ return logicalTextureUnit;
+ }
+
+ return -1;
+}
+
+// Returns the texture type for a given Direct3D 9 sampler type and
+// index (0-15 for the pixel shader and 0-3 for the vertex shader).
+TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
+{
+ switch (type)
+ {
+ case SAMPLER_PIXEL:
+ ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
+ ASSERT(mSamplersPS[samplerIndex].active);
+ return mSamplersPS[samplerIndex].textureType;
+ case SAMPLER_VERTEX:
+ ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
+ ASSERT(mSamplersVS[samplerIndex].active);
+ return mSamplersVS[samplerIndex].textureType;
+ default: UNREACHABLE();
+ }
+
+ return TEXTURE_2D;
+}
+
+GLint ProgramBinary::getUniformLocation(std::string name)
+{
+ unsigned int subscript = 0;
+
+ // 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);
+ }
+
+ unsigned int numUniforms = mUniformIndex.size();
+ for (unsigned int location = 0; location < numUniforms; location++)
+ {
+ if (mUniformIndex[location].name == name &&
+ mUniformIndex[location].element == subscript)
+ {
+ return location;
+ }
+ }
+
+ return -1;
+}
+
+bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+
+ if (targetUniform->type == GL_FLOAT)
+ {
+ GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ target[0] = v[0];
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ target += 4;
+ v += 1;
+ }
+ }
+ else if (targetUniform->type == GL_BOOL)
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams[1] = GL_FALSE;
+ boolParams[2] = GL_FALSE;
+ boolParams[3] = GL_FALSE;
+ boolParams += 4;
+ v += 1;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+
+ if (targetUniform->type == GL_FLOAT_VEC2)
+ {
+ GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ target[0] = v[0];
+ target[1] = v[1];
+ target[2] = 0;
+ target[3] = 0;
+ target += 4;
+ v += 2;
+ }
+ }
+ else if (targetUniform->type == GL_BOOL_VEC2)
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams[2] = GL_FALSE;
+ boolParams[3] = GL_FALSE;
+ boolParams += 4;
+ v += 2;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+
+ if (targetUniform->type == GL_FLOAT_VEC3)
+ {
+ GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ target[0] = v[0];
+ target[1] = v[1];
+ target[2] = v[2];
+ target[3] = 0;
+ target += 4;
+ v += 3;
+ }
+ }
+ else if (targetUniform->type == GL_BOOL_VEC3)
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams[3] = GL_FALSE;
+ boolParams += 4;
+ v += 3;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+
+ if (targetUniform->type == GL_FLOAT_VEC4)
+ {
+ GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ target[0] = v[0];
+ target[1] = v[1];
+ target[2] = v[2];
+ target[3] = v[3];
+ target += 4;
+ v += 4;
+ }
+ }
+ else if (targetUniform->type == GL_BOOL_VEC4)
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE;
+ boolParams += 4;
+ v += 4;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
+void transposeMatrix(T *target, const GLfloat *value)
+{
+ int copyWidth = std::min(targetWidth, srcWidth);
+ int copyHeight = std::min(targetHeight, srcHeight);
+
+ for (int x = 0; x < copyWidth; x++)
+ {
+ for (int y = 0; y < copyHeight; y++)
+ {
+ target[x * targetWidth + y] = (T)value[y * srcWidth + x];
+ }
+ }
+ // clear unfilled right side
+ for (int y = 0; y < copyHeight; y++)
+ {
+ for (int x = srcWidth; x < targetWidth; x++)
+ {
+ target[y * targetWidth + x] = (T)0;
+ }
+ }
+ // clear unfilled bottom.
+ for (int y = srcHeight; y < targetHeight; y++)
+ {
+ for (int x = 0; x < targetWidth; x++)
+ {
+ target[y * targetWidth + x] = (T)0;
+ }
+ }
+}
+
+bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type != GL_FLOAT_MAT2)
+ {
+ return false;
+ }
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+ GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
+
+ for (int i = 0; i < count; i++)
+ {
+ transposeMatrix<GLfloat,4,2,2,2>(target, value);
+ target += 8;
+ value += 4;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type != GL_FLOAT_MAT3)
+ {
+ return false;
+ }
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+ GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
+
+ for (int i = 0; i < count; i++)
+ {
+ transposeMatrix<GLfloat,4,3,3,3>(target, value);
+ target += 12;
+ value += 9;
+ }
+
+ return true;
+}
+
+
+bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type != GL_FLOAT_MAT4)
+ {
+ return false;
+ }
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+ GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
+
+ for (int i = 0; i < count; i++)
+ {
+ transposeMatrix<GLfloat,4,4,4,4>(target, value);
+ target += 16;
+ value += 16;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+
+ if (targetUniform->type == GL_INT ||
+ targetUniform->type == GL_SAMPLER_2D ||
+ targetUniform->type == GL_SAMPLER_CUBE)
+ {
+ GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ target[0] = v[0];
+ target[1] = 0;
+ target[2] = 0;
+ target[3] = 0;
+ target += 4;
+ v += 1;
+ }
+ }
+ else if (targetUniform->type == GL_BOOL)
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams[1] = GL_FALSE;
+ boolParams[2] = GL_FALSE;
+ boolParams[3] = GL_FALSE;
+ boolParams += 4;
+ v += 1;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+
+ if (targetUniform->type == GL_INT_VEC2)
+ {
+ GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ target[0] = v[0];
+ target[1] = v[1];
+ target[2] = 0;
+ target[3] = 0;
+ target += 4;
+ v += 2;
+ }
+ }
+ else if (targetUniform->type == GL_BOOL_VEC2)
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams[2] = GL_FALSE;
+ boolParams[3] = GL_FALSE;
+ boolParams += 4;
+ v += 2;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+
+ if (targetUniform->type == GL_INT_VEC3)
+ {
+ GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ target[0] = v[0];
+ target[1] = v[1];
+ target[2] = v[2];
+ target[3] = 0;
+ target += 4;
+ v += 3;
+ }
+ }
+ else if (targetUniform->type == GL_BOOL_VEC3)
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams[3] = GL_FALSE;
+ boolParams += 4;
+ v += 3;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ int elementCount = targetUniform->elementCount();
+
+ if (elementCount == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+
+ if (targetUniform->type == GL_INT_VEC4)
+ {
+ GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ target[0] = v[0];
+ target[1] = v[1];
+ target[2] = v[2];
+ target[3] = v[3];
+ target += 4;
+ v += 4;
+ }
+ }
+ else if (targetUniform->type == GL_BOOL_VEC4)
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (int i = 0; i < count; i++)
+ {
+ boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE;
+ boolParams += 4;
+ v += 4;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ // sized queries -- ensure the provided buffer is large enough
+ if (bufSize)
+ {
+ int requiredBytes = UniformExternalSize(targetUniform->type);
+ if (*bufSize < requiredBytes)
+ {
+ return false;
+ }
+ }
+
+ switch (targetUniform->type)
+ {
+ case GL_FLOAT_MAT2:
+ transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
+ break;
+ case GL_FLOAT_MAT3:
+ transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
+ break;
+ case GL_FLOAT_MAT4:
+ transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
+ break;
+ default:
+ {
+ unsigned int size = UniformComponentCount(targetUniform->type);
+
+ switch (UniformComponentType(targetUniform->type))
+ {
+ case GL_BOOL:
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (unsigned int i = 0; i < size; i++)
+ {
+ params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
+ }
+ }
+ break;
+ case GL_FLOAT:
+ memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
+ size * sizeof(GLfloat));
+ break;
+ case GL_INT:
+ {
+ GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (unsigned int i = 0; i < size; i++)
+ {
+ params[i] = (float)intParams[i];
+ }
+ }
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ // sized queries -- ensure the provided buffer is large enough
+ if (bufSize)
+ {
+ int requiredBytes = UniformExternalSize(targetUniform->type);
+ if (*bufSize < requiredBytes)
+ {
+ return false;
+ }
+ }
+
+ switch (targetUniform->type)
+ {
+ case GL_FLOAT_MAT2:
+ transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
+ break;
+ case GL_FLOAT_MAT3:
+ transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
+ break;
+ case GL_FLOAT_MAT4:
+ transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
+ break;
+ default:
+ {
+ unsigned int size = VariableColumnCount(targetUniform->type);
+
+ switch (UniformComponentType(targetUniform->type))
+ {
+ case GL_BOOL:
+ {
+ GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (unsigned int i = 0; i < size; i++)
+ {
+ params[i] = boolParams[i];
+ }
+ }
+ break;
+ case GL_FLOAT:
+ {
+ GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+
+ for (unsigned int i = 0; i < size; i++)
+ {
+ params[i] = (GLint)floatParams[i];
+ }
+ }
+ break;
+ case GL_INT:
+ memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
+ size * sizeof(GLint));
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+
+ return true;
+}
+
+void ProgramBinary::dirtyAllUniforms()
+{
+ unsigned int numUniforms = mUniforms.size();
+ for (unsigned int index = 0; index < numUniforms; index++)
+ {
+ mUniforms[index]->dirty = true;
+ }
+}
+
+// Applies all the uniforms set for this program object to the renderer
+void ProgramBinary::applyUniforms()
+{
+ // Retrieve sampler uniform values
+ for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
+ {
+ Uniform *targetUniform = *ub;
+
+ if (targetUniform->dirty)
+ {
+ if (targetUniform->type == GL_SAMPLER_2D ||
+ targetUniform->type == GL_SAMPLER_CUBE)
+ {
+ int count = targetUniform->elementCount();
+ GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
+
+ if (targetUniform->psRegisterIndex >= 0)
+ {
+ unsigned int firstIndex = targetUniform->psRegisterIndex;
+
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int samplerIndex = firstIndex + i;
+
+ if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
+ {
+ ASSERT(mSamplersPS[samplerIndex].active);
+ mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
+ }
+ }
+ }
+
+ if (targetUniform->vsRegisterIndex >= 0)
+ {
+ unsigned int firstIndex = targetUniform->vsRegisterIndex;
+
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int samplerIndex = firstIndex + i;
+
+ if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
+ {
+ ASSERT(mSamplersVS[samplerIndex].active);
+ mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ mRenderer->applyUniforms(this, &mUniforms);
+}
+
+// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
+// Returns the number of used varying registers, or -1 if unsuccesful
+int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
+{
+ const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
+
+ fragmentShader->resetVaryingsRegisterAssignment();
+
+ for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
+ {
+ int n = VariableRowCount(varying->type) * varying->size;
+ int m = VariableColumnCount(varying->type);
+ bool success = false;
+
+ if (m == 2 || m == 3 || m == 4)
+ {
+ for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
+ {
+ bool available = true;
+
+ for (int y = 0; y < n && available; y++)
+ {
+ for (int x = 0; x < m && available; x++)
+ {
+ if (packing[r + y][x])
+ {
+ available = false;
+ }
+ }
+ }
+
+ if (available)
+ {
+ varying->reg = r;
+ varying->col = 0;
+
+ for (int y = 0; y < n; y++)
+ {
+ for (int x = 0; x < m; x++)
+ {
+ packing[r + y][x] = &*varying;
+ }
+ }
+
+ success = true;
+ }
+ }
+
+ if (!success && m == 2)
+ {
+ for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
+ {
+ bool available = true;
+
+ for (int y = 0; y < n && available; y++)
+ {
+ for (int x = 2; x < 4 && available; x++)
+ {
+ if (packing[r + y][x])
+ {
+ available = false;
+ }
+ }
+ }
+
+ if (available)
+ {
+ varying->reg = r;
+ varying->col = 2;
+
+ for (int y = 0; y < n; y++)
+ {
+ for (int x = 2; x < 4; x++)
+ {
+ packing[r + y][x] = &*varying;
+ }
+ }
+
+ success = true;
+ }
+ }
+ }
+ }
+ else if (m == 1)
+ {
+ int space[4] = {0};
+
+ for (int y = 0; y < maxVaryingVectors; y++)
+ {
+ for (int x = 0; x < 4; x++)
+ {
+ space[x] += packing[y][x] ? 0 : 1;
+ }
+ }
+
+ int column = 0;
+
+ for (int x = 0; x < 4; x++)
+ {
+ if (space[x] >= n && space[x] < space[column])
+ {
+ column = x;
+ }
+ }
+
+ if (space[column] >= n)
+ {
+ for (int r = 0; r < maxVaryingVectors; r++)
+ {
+ if (!packing[r][column])
+ {
+ varying->reg = r;
+
+ for (int y = r; y < r + n; y++)
+ {
+ packing[y][column] = &*varying;
+ }
+
+ break;
+ }
+ }
+
+ varying->col = column;
+
+ success = true;
+ }
+ }
+ else UNREACHABLE();
+
+ if (!success)
+ {
+ infoLog.append("Could not pack varying %s", varying->name.c_str());
+
+ return -1;
+ }
+ }
+
+ // Return the number of used registers
+ int registers = 0;
+
+ for (int r = 0; r < maxVaryingVectors; r++)
+ {
+ if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
+ {
+ registers++;
+ }
+ }
+
+ return registers;
+}
+
+bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
+ std::string& pixelHLSL, std::string& vertexHLSL,
+ FragmentShader *fragmentShader, VertexShader *vertexShader)
+{
+ if (pixelHLSL.empty() || vertexHLSL.empty())
+ {
+ return false;
+ }
+
+ bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
+ bool usesFragColor = fragmentShader->mUsesFragColor;
+ bool usesFragData = fragmentShader->mUsesFragData;
+ if (usesFragColor && usesFragData)
+ {
+ infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
+ return false;
+ }
+
+ // Write the HLSL input/output declarations
+ const int shaderModel = mRenderer->getMajorShaderModel();
+ const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
+
+ const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
+
+ // The output color is broadcast to all enabled draw buffers when writing to gl_FragColor
+ const bool broadcast = fragmentShader->mUsesFragColor;
+ const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
+
+ if (registersNeeded > maxVaryingVectors)
+ {
+ infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
+
+ return false;
+ }
+
+ vertexShader->resetVaryingsRegisterAssignment();
+
+ for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
+ {
+ bool matched = false;
+
+ for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
+ {
+ if (output->name == input->name)
+ {
+ if (output->type != input->type || output->size != input->size)
+ {
+ infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
+
+ return false;
+ }
+
+ output->reg = input->reg;
+ output->col = input->col;
+
+ matched = true;
+ break;
+ }
+ }
+
+ if (!matched)
+ {
+ infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
+
+ return false;
+ }
+ }
+
+ mUsesPointSize = vertexShader->mUsesPointSize;
+ std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
+ std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
+ std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
+ std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
+
+ // special varyings that use reserved registers
+ int reservedRegisterIndex = registers;
+ std::string fragCoordSemantic;
+ std::string pointCoordSemantic;
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
+ }
+
+ if (fragmentShader->mUsesPointCoord)
+ {
+ // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
+ // In DX11 we compute this in the GS.
+ if (shaderModel == 3)
+ {
+ pointCoordSemantic = "TEXCOORD0";
+ }
+ else if (shaderModel >= 4)
+ {
+ pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
+ }
+ }
+
+ vertexHLSL += "struct VS_INPUT\n"
+ "{\n";
+
+ int semanticIndex = 0;
+ for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+ {
+ switch (attribute->type)
+ {
+ case GL_FLOAT: vertexHLSL += " float "; break;
+ case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
+ case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
+ case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
+ case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
+ case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
+ case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
+ default: UNREACHABLE();
+ }
+
+ vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
+
+ semanticIndex += VariableRowCount(attribute->type);
+ }
+
+ vertexHLSL += "};\n"
+ "\n"
+ "struct VS_OUTPUT\n"
+ "{\n";
+
+ if (shaderModel < 4)
+ {
+ vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
+ }
+
+ for (int r = 0; r < registers; r++)
+ {
+ int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
+
+ vertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
+ }
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+ }
+
+ if (vertexShader->mUsesPointSize && shaderModel >= 3)
+ {
+ vertexHLSL += " float gl_PointSize : PSIZE;\n";
+ }
+
+ if (shaderModel >= 4)
+ {
+ vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
+ }
+
+ vertexHLSL += "};\n"
+ "\n"
+ "VS_OUTPUT main(VS_INPUT input)\n"
+ "{\n";
+
+ for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+ {
+ vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
+
+ if (VariableRowCount(attribute->type) > 1) // Matrix
+ {
+ vertexHLSL += "transpose";
+ }
+
+ vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
+ }
+
+ if (shaderModel >= 4)
+ {
+ vertexHLSL += "\n"
+ " gl_main();\n"
+ "\n"
+ " VS_OUTPUT output;\n"
+ " output.gl_Position.x = gl_Position.x;\n"
+ " output.gl_Position.y = -gl_Position.y;\n"
+ " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
+ " output.gl_Position.w = gl_Position.w;\n";
+ }
+ else
+ {
+ vertexHLSL += "\n"
+ " gl_main();\n"
+ "\n"
+ " VS_OUTPUT output;\n"
+ " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
+ " output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
+ " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
+ " output.gl_Position.w = gl_Position.w;\n";
+ }
+
+ if (vertexShader->mUsesPointSize && shaderModel >= 3)
+ {
+ vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
+ }
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
+ }
+
+ for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
+ {
+ if (varying->reg >= 0)
+ {
+ for (int i = 0; i < varying->size; i++)
+ {
+ int rows = VariableRowCount(varying->type);
+
+ for (int j = 0; j < rows; j++)
+ {
+ int r = varying->reg + i * rows + j;
+ vertexHLSL += " output.v" + str(r);
+
+ bool sharedRegister = false; // Register used by multiple varyings
+
+ for (int x = 0; x < 4; x++)
+ {
+ if (packing[r][x] && packing[r][x] != packing[r][0])
+ {
+ sharedRegister = true;
+ break;
+ }
+ }
+
+ if(sharedRegister)
+ {
+ vertexHLSL += ".";
+
+ for (int x = 0; x < 4; x++)
+ {
+ if (packing[r][x] == &*varying)
+ {
+ switch(x)
+ {
+ case 0: vertexHLSL += "x"; break;
+ case 1: vertexHLSL += "y"; break;
+ case 2: vertexHLSL += "z"; break;
+ case 3: vertexHLSL += "w"; break;
+ }
+ }
+ }
+ }
+
+ vertexHLSL += " = " + varying->name;
+
+ if (varying->array)
+ {
+ vertexHLSL += "[" + str(i) + "]";
+ }
+
+ if (rows > 1)
+ {
+ vertexHLSL += "[" + str(j) + "]";
+ }
+
+ vertexHLSL += ";\n";
+ }
+ }
+ }
+ }
+
+ vertexHLSL += "\n"
+ " return output;\n"
+ "}\n";
+
+ pixelHLSL += "struct PS_INPUT\n"
+ "{\n";
+
+ for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
+ {
+ if (varying->reg >= 0)
+ {
+ for (int i = 0; i < varying->size; i++)
+ {
+ int rows = VariableRowCount(varying->type);
+ for (int j = 0; j < rows; j++)
+ {
+ std::string n = str(varying->reg + i * rows + j);
+ pixelHLSL += " float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
+ }
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+ }
+
+ if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
+ {
+ pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
+ }
+
+ // Must consume the PSIZE element if the geometry shader is not active
+ // We won't know if we use a GS until we draw
+ if (vertexShader->mUsesPointSize && shaderModel >= 4)
+ {
+ pixelHLSL += " float gl_PointSize : PSIZE;\n";
+ }
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ if (shaderModel >= 4)
+ {
+ pixelHLSL += " float4 dx_VPos : SV_Position;\n";
+ }
+ else if (shaderModel >= 3)
+ {
+ pixelHLSL += " float2 dx_VPos : VPOS;\n";
+ }
+ }
+
+ pixelHLSL += "};\n"
+ "\n"
+ "struct PS_OUTPUT\n"
+ "{\n";
+
+ for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
+ {
+ pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
+ }
+
+ if (fragmentShader->mUsesFragDepth)
+ {
+ pixelHLSL += " float gl_Depth : " + depthSemantic + ";\n";
+ }
+
+ pixelHLSL += "};\n"
+ "\n";
+
+ if (fragmentShader->mUsesFrontFacing)
+ {
+ if (shaderModel >= 4)
+ {
+ pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
+ "{\n";
+ }
+ else
+ {
+ pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
+ "{\n";
+ }
+ }
+ else
+ {
+ pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
+ "{\n";
+ }
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
+
+ if (shaderModel >= 4)
+ {
+ pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
+ " gl_FragCoord.y = input.dx_VPos.y;\n";
+ }
+ else if (shaderModel >= 3)
+ {
+ pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
+ " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
+ }
+ else
+ {
+ // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
+ pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
+ " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
+ }
+
+ pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
+ " gl_FragCoord.w = rhw;\n";
+ }
+
+ if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
+ {
+ pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
+ pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
+ }
+
+ if (fragmentShader->mUsesFrontFacing)
+ {
+ if (shaderModel <= 3)
+ {
+ pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
+ }
+ else
+ {
+ pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
+ }
+ }
+
+ for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
+ {
+ if (varying->reg >= 0)
+ {
+ for (int i = 0; i < varying->size; i++)
+ {
+ int rows = VariableRowCount(varying->type);
+ for (int j = 0; j < rows; j++)
+ {
+ std::string n = str(varying->reg + i * rows + j);
+ pixelHLSL += " " + varying->name;
+
+ if (varying->array)
+ {
+ pixelHLSL += "[" + str(i) + "]";
+ }
+
+ if (rows > 1)
+ {
+ pixelHLSL += "[" + str(j) + "]";
+ }
+
+ switch (VariableColumnCount(varying->type))
+ {
+ case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
+ case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
+ case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
+ case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ pixelHLSL += "\n"
+ " gl_main();\n"
+ "\n"
+ " PS_OUTPUT output;\n";
+
+ for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
+ {
+ unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
+
+ pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
+ }
+
+ if (fragmentShader->mUsesFragDepth)
+ {
+ pixelHLSL += " output.gl_Depth = gl_Depth;\n";
+ }
+
+ pixelHLSL += "\n"
+ " return output;\n"
+ "}\n";
+
+ return true;
+}
+
+bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
+{
+ BinaryInputStream stream(binary, length);
+
+ int format = 0;
+ stream.read(&format);
+ if (format != GL_PROGRAM_BINARY_ANGLE)
+ {
+ infoLog.append("Invalid program binary format.");
+ return false;
+ }
+
+ int version = 0;
+ stream.read(&version);
+ if (version != VERSION_DWORD)
+ {
+ infoLog.append("Invalid program binary version.");
+ return false;
+ }
+
+ int compileFlags = 0;
+ stream.read(&compileFlags);
+ if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
+ {
+ infoLog.append("Mismatched compilation flags.");
+ return false;
+ }
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
+ {
+ stream.read(&mLinkedAttribute[i].type);
+ std::string name;
+ stream.read(&name);
+ mLinkedAttribute[i].name = name;
+ stream.read(&mSemanticIndex[i]);
+ }
+
+ for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
+ {
+ stream.read(&mSamplersPS[i].active);
+ stream.read(&mSamplersPS[i].logicalTextureUnit);
+
+ int textureType;
+ stream.read(&textureType);
+ mSamplersPS[i].textureType = (TextureType) textureType;
+ }
+
+ for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
+ {
+ stream.read(&mSamplersVS[i].active);
+ stream.read(&mSamplersVS[i].logicalTextureUnit);
+
+ int textureType;
+ stream.read(&textureType);
+ mSamplersVS[i].textureType = (TextureType) textureType;
+ }
+
+ stream.read(&mUsedVertexSamplerRange);
+ stream.read(&mUsedPixelSamplerRange);
+ stream.read(&mUsesPointSize);
+
+ size_t size;
+ stream.read(&size);
+ if (stream.error())
+ {
+ infoLog.append("Invalid program binary.");
+ return false;
+ }
+
+ mUniforms.resize(size);
+ for (unsigned int i = 0; i < size; ++i)
+ {
+ GLenum type;
+ GLenum precision;
+ std::string name;
+ unsigned int arraySize;
+
+ stream.read(&type);
+ stream.read(&precision);
+ stream.read(&name);
+ stream.read(&arraySize);
+
+ mUniforms[i] = new Uniform(type, precision, name, arraySize);
+
+ stream.read(&mUniforms[i]->psRegisterIndex);
+ stream.read(&mUniforms[i]->vsRegisterIndex);
+ stream.read(&mUniforms[i]->registerCount);
+ }
+
+ stream.read(&size);
+ if (stream.error())
+ {
+ infoLog.append("Invalid program binary.");
+ return false;
+ }
+
+ mUniformIndex.resize(size);
+ for (unsigned int i = 0; i < size; ++i)
+ {
+ stream.read(&mUniformIndex[i].name);
+ stream.read(&mUniformIndex[i].element);
+ stream.read(&mUniformIndex[i].index);
+ }
+
+ unsigned int pixelShaderSize;
+ stream.read(&pixelShaderSize);
+
+ unsigned int vertexShaderSize;
+ stream.read(&vertexShaderSize);
+
+ unsigned int geometryShaderSize;
+ stream.read(&geometryShaderSize);
+
+ const char *ptr = (const char*) binary + stream.offset();
+
+ const GUID *binaryIdentifier = (const GUID *) ptr;
+ ptr += sizeof(GUID);
+
+ GUID identifier = mRenderer->getAdapterIdentifier();
+ if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
+ {
+ infoLog.append("Invalid program binary.");
+ return false;
+ }
+
+ const char *pixelShaderFunction = ptr;
+ ptr += pixelShaderSize;
+
+ const char *vertexShaderFunction = ptr;
+ ptr += vertexShaderSize;
+
+ const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
+ ptr += geometryShaderSize;
+
+ mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
+ pixelShaderSize, rx::SHADER_PIXEL);
+ if (!mPixelExecutable)
+ {
+ infoLog.append("Could not create pixel shader.");
+ return false;
+ }
+
+ mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
+ vertexShaderSize, rx::SHADER_VERTEX);
+ if (!mVertexExecutable)
+ {
+ infoLog.append("Could not create vertex shader.");
+ delete mPixelExecutable;
+ mPixelExecutable = NULL;
+ return false;
+ }
+
+ if (geometryShaderFunction != NULL && geometryShaderSize > 0)
+ {
+ mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
+ geometryShaderSize, rx::SHADER_GEOMETRY);
+ if (!mGeometryExecutable)
+ {
+ infoLog.append("Could not create geometry shader.");
+ delete mPixelExecutable;
+ mPixelExecutable = NULL;
+ delete mVertexExecutable;
+ mVertexExecutable = NULL;
+ return false;
+ }
+ }
+ else
+ {
+ mGeometryExecutable = NULL;
+ }
+
+ return true;
+}
+
+bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
+{
+ BinaryOutputStream stream;
+
+ stream.write(GL_PROGRAM_BINARY_ANGLE);
+ stream.write(VERSION_DWORD);
+ stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
+
+ for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
+ {
+ stream.write(mLinkedAttribute[i].type);
+ stream.write(mLinkedAttribute[i].name);
+ stream.write(mSemanticIndex[i]);
+ }
+
+ for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
+ {
+ stream.write(mSamplersPS[i].active);
+ stream.write(mSamplersPS[i].logicalTextureUnit);
+ stream.write((int) mSamplersPS[i].textureType);
+ }
+
+ for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
+ {
+ stream.write(mSamplersVS[i].active);
+ stream.write(mSamplersVS[i].logicalTextureUnit);
+ stream.write((int) mSamplersVS[i].textureType);
+ }
+
+ stream.write(mUsedVertexSamplerRange);
+ stream.write(mUsedPixelSamplerRange);
+ stream.write(mUsesPointSize);
+
+ stream.write(mUniforms.size());
+ for (unsigned int i = 0; i < mUniforms.size(); ++i)
+ {
+ stream.write(mUniforms[i]->type);
+ stream.write(mUniforms[i]->precision);
+ stream.write(mUniforms[i]->name);
+ stream.write(mUniforms[i]->arraySize);
+
+ stream.write(mUniforms[i]->psRegisterIndex);
+ stream.write(mUniforms[i]->vsRegisterIndex);
+ stream.write(mUniforms[i]->registerCount);
+ }
+
+ stream.write(mUniformIndex.size());
+ for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
+ {
+ stream.write(mUniformIndex[i].name);
+ stream.write(mUniformIndex[i].element);
+ stream.write(mUniformIndex[i].index);
+ }
+
+ UINT pixelShaderSize = mPixelExecutable->getLength();
+ stream.write(pixelShaderSize);
+
+ UINT vertexShaderSize = mVertexExecutable->getLength();
+ stream.write(vertexShaderSize);
+
+ UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
+ stream.write(geometryShaderSize);
+
+ GUID identifier = mRenderer->getAdapterIdentifier();
+
+ GLsizei streamLength = stream.length();
+ const void *streamData = stream.data();
+
+ GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
+ if (totalLength > bufSize)
+ {
+ if (length)
+ {
+ *length = 0;
+ }
+
+ return false;
+ }
+
+ if (binary)
+ {
+ char *ptr = (char*) binary;
+
+ memcpy(ptr, streamData, streamLength);
+ ptr += streamLength;
+
+ memcpy(ptr, &identifier, sizeof(GUID));
+ ptr += sizeof(GUID);
+
+ memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
+ ptr += pixelShaderSize;
+
+ memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
+ ptr += vertexShaderSize;
+
+ if (mGeometryExecutable != NULL && geometryShaderSize > 0)
+ {
+ memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
+ ptr += geometryShaderSize;
+ }
+
+ ASSERT(ptr - totalLength == binary);
+ }
+
+ if (length)
+ {
+ *length = totalLength;
+ }
+
+ return true;
+}
+
+GLint ProgramBinary::getLength()
+{
+ GLint length;
+ if (save(NULL, INT_MAX, &length))
+ {
+ return length;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
+{
+ if (!fragmentShader || !fragmentShader->isCompiled())
+ {
+ return false;
+ }
+
+ if (!vertexShader || !vertexShader->isCompiled())
+ {
+ return false;
+ }
+
+ std::string pixelHLSL = fragmentShader->getHLSL();
+ std::string vertexHLSL = vertexShader->getHLSL();
+
+ // Map the varyings to the register file
+ const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
+ int registers = packVaryings(infoLog, packing, fragmentShader);
+
+ if (registers < 0)
+ {
+ return false;
+ }
+
+ if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
+ {
+ return false;
+ }
+
+ bool success = true;
+
+ if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
+ {
+ success = false;
+ }
+
+ if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
+ {
+ success = false;
+ }
+
+ // special case for gl_DepthRange, the only built-in uniform (also a struct)
+ if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
+ {
+ mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0));
+ mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0));
+ mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0));
+ }
+
+ if (success)
+ {
+ mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
+ mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
+
+ if (usesGeometryShader())
+ {
+ std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
+ mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
+ }
+
+ if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
+ {
+ infoLog.append("Failed to create D3D shaders.");
+ success = false;
+
+ delete mVertexExecutable;
+ mVertexExecutable = NULL;
+ delete mPixelExecutable;
+ mPixelExecutable = NULL;
+ delete mGeometryExecutable;
+ mGeometryExecutable = NULL;
+ }
+ }
+
+ return success;
+}
+
+// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
+bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
+{
+ unsigned int usedLocations = 0;
+
+ // Link attributes that have a binding location
+ for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+ {
+ int location = attributeBindings.getAttributeBinding(attribute->name);
+
+ if (location != -1) // Set by glBindAttribLocation
+ {
+ if (!mLinkedAttribute[location].name.empty())
+ {
+ // Multiple active attributes bound to the same location; not an error
+ }
+
+ mLinkedAttribute[location] = *attribute;
+
+ int rows = VariableRowCount(attribute->type);
+
+ if (rows + location > MAX_VERTEX_ATTRIBS)
+ {
+ infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
+
+ return false;
+ }
+
+ for (int i = 0; i < rows; i++)
+ {
+ usedLocations |= 1 << (location + i);
+ }
+ }
+ }
+
+ // Link attributes that don't have a binding location
+ for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+ {
+ int location = attributeBindings.getAttributeBinding(attribute->name);
+
+ if (location == -1) // Not set by glBindAttribLocation
+ {
+ int rows = VariableRowCount(attribute->type);
+ int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
+
+ if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
+ {
+ infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
+
+ return false; // Fail to link
+ }
+
+ mLinkedAttribute[availableIndex] = *attribute;
+ }
+ }
+
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
+ {
+ int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
+ int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
+
+ for (int r = 0; r < rows; r++)
+ {
+ mSemanticIndex[attributeIndex++] = index++;
+ }
+ }
+
+ return true;
+}
+
+bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
+{
+ for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
+ {
+ if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
+ {
+ return false;
+ }
+ }
+
+ for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
+ {
+ if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
+{
+ if (constant.type == GL_SAMPLER_2D ||
+ constant.type == GL_SAMPLER_CUBE)
+ {
+ unsigned int samplerIndex = constant.registerIndex;
+
+ do
+ {
+ if (shader == GL_VERTEX_SHADER)
+ {
+ if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
+ {
+ mSamplersVS[samplerIndex].active = true;
+ mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
+ mSamplersVS[samplerIndex].logicalTextureUnit = 0;
+ mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
+ }
+ else
+ {
+ infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
+ return false;
+ }
+ }
+ else if (shader == GL_FRAGMENT_SHADER)
+ {
+ if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
+ {
+ mSamplersPS[samplerIndex].active = true;
+ mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
+ mSamplersPS[samplerIndex].logicalTextureUnit = 0;
+ mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
+ }
+ else
+ {
+ infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
+ return false;
+ }
+ }
+ else UNREACHABLE();
+
+ samplerIndex++;
+ }
+ while (samplerIndex < constant.registerIndex + constant.arraySize);
+ }
+
+ Uniform *uniform = NULL;
+ GLint location = getUniformLocation(constant.name);
+
+ if (location >= 0) // Previously defined, type and precision must match
+ {
+ uniform = mUniforms[mUniformIndex[location].index];
+
+ if (uniform->type != constant.type)
+ {
+ infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
+ return false;
+ }
+
+ if (uniform->precision != constant.precision)
+ {
+ infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
+ return false;
+ }
+ }
+ else
+ {
+ uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
+ }
+
+ if (!uniform)
+ {
+ return false;
+ }
+
+ if (shader == GL_FRAGMENT_SHADER)
+ {
+ uniform->psRegisterIndex = constant.registerIndex;
+ }
+ else if (shader == GL_VERTEX_SHADER)
+ {
+ uniform->vsRegisterIndex = constant.registerIndex;
+ }
+ else UNREACHABLE();
+
+ if (location >= 0)
+ {
+ return uniform->type == constant.type;
+ }
+
+ mUniforms.push_back(uniform);
+ unsigned int uniformIndex = mUniforms.size() - 1;
+
+ for (unsigned int i = 0; i < uniform->elementCount(); i++)
+ {
+ mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
+ }
+
+ if (shader == GL_VERTEX_SHADER)
+ {
+ if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
+ {
+ infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
+ return false;
+ }
+ }
+ else if (shader == GL_FRAGMENT_SHADER)
+ {
+ if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
+ {
+ infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
+ return false;
+ }
+ }
+ else UNREACHABLE();
+
+ return true;
+}
+
+std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
+{
+ // for now we only handle point sprite emulation
+ ASSERT(usesPointSpriteEmulation());
+ return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
+}
+
+std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
+{
+ ASSERT(registers >= 0);
+ ASSERT(vertexShader->mUsesPointSize);
+ ASSERT(mRenderer->getMajorShaderModel() >= 4);
+
+ std::string geomHLSL;
+
+ std::string varyingSemantic = "TEXCOORD";
+
+ std::string fragCoordSemantic;
+ std::string pointCoordSemantic;
+
+ int reservedRegisterIndex = registers;
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
+ }
+
+ if (fragmentShader->mUsesPointCoord)
+ {
+ pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
+ }
+
+ geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
+ "\n"
+ "struct GS_INPUT\n"
+ "{\n";
+
+ for (int r = 0; r < registers; r++)
+ {
+ int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
+
+ geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
+ }
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+ }
+
+ geomHLSL += " float gl_PointSize : PSIZE;\n"
+ " float4 gl_Position : SV_Position;\n"
+ "};\n"
+ "\n"
+ "struct GS_OUTPUT\n"
+ "{\n";
+
+ for (int r = 0; r < registers; r++)
+ {
+ int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
+
+ geomHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
+ }
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+ }
+
+ if (fragmentShader->mUsesPointCoord)
+ {
+ geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
+ }
+
+ geomHLSL += " float gl_PointSize : PSIZE;\n"
+ " float4 gl_Position : SV_Position;\n"
+ "};\n"
+ "\n"
+ "static float2 pointSpriteCorners[] = \n"
+ "{\n"
+ " float2( 0.5f, -0.5f),\n"
+ " float2( 0.5f, 0.5f),\n"
+ " float2(-0.5f, -0.5f),\n"
+ " float2(-0.5f, 0.5f)\n"
+ "};\n"
+ "\n"
+ "static float2 pointSpriteTexcoords[] = \n"
+ "{\n"
+ " float2(1.0f, 1.0f),\n"
+ " float2(1.0f, 0.0f),\n"
+ " float2(0.0f, 1.0f),\n"
+ " float2(0.0f, 0.0f)\n"
+ "};\n"
+ "\n"
+ "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
+ "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
+ "\n"
+ "[maxvertexcount(4)]\n"
+ "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
+ "{\n"
+ " GS_OUTPUT output = (GS_OUTPUT)0;\n"
+ " output.gl_PointSize = input[0].gl_PointSize;\n";
+
+ for (int r = 0; r < registers; r++)
+ {
+ geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
+ }
+
+ if (fragmentShader->mUsesFragCoord)
+ {
+ geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
+ }
+
+ geomHLSL += " \n"
+ " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
+ " float4 gl_Position = input[0].gl_Position;\n"
+ " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n";
+
+ for (int corner = 0; corner < 4; corner++)
+ {
+ geomHLSL += " \n"
+ " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
+
+ if (fragmentShader->mUsesPointCoord)
+ {
+ geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
+ }
+
+ geomHLSL += " outStream.Append(output);\n";
+ }
+
+ geomHLSL += " \n"
+ " outStream.RestartStrip();\n"
+ "}\n";
+
+ return geomHLSL;
+}
+
+// This method needs to match OutputHLSL::decorate
+std::string ProgramBinary::decorateAttribute(const std::string &name)
+{
+ if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
+ {
+ return "_" + name;
+ }
+
+ return name;
+}
+
+bool ProgramBinary::isValidated() const
+{
+ return mValidated;
+}
+
+void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
+{
+ // Skip over inactive attributes
+ unsigned int activeAttribute = 0;
+ unsigned int attribute;
+ for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
+ {
+ if (mLinkedAttribute[attribute].name.empty())
+ {
+ continue;
+ }
+
+ if (activeAttribute == index)
+ {
+ break;
+ }
+
+ activeAttribute++;
+ }
+
+ if (bufsize > 0)
+ {
+ const char *string = mLinkedAttribute[attribute].name.c_str();
+
+ strncpy(name, string, bufsize);
+ name[bufsize - 1] = '\0';
+
+ if (length)
+ {
+ *length = strlen(name);
+ }
+ }
+
+ *size = 1; // Always a single 'type' instance
+
+ *type = mLinkedAttribute[attribute].type;
+}
+
+GLint ProgramBinary::getActiveAttributeCount() const
+{
+ int count = 0;
+
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ if (!mLinkedAttribute[attributeIndex].name.empty())
+ {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+GLint ProgramBinary::getActiveAttributeMaxLength() const
+{
+ int maxLength = 0;
+
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ if (!mLinkedAttribute[attributeIndex].name.empty())
+ {
+ maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
+ }
+ }
+
+ return maxLength;
+}
+
+void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
+{
+ ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
+
+ if (bufsize > 0)
+ {
+ std::string string = mUniforms[index]->name;
+
+ if (mUniforms[index]->isArray())
+ {
+ string += "[0]";
+ }
+
+ strncpy(name, string.c_str(), bufsize);
+ name[bufsize - 1] = '\0';
+
+ if (length)
+ {
+ *length = strlen(name);
+ }
+ }
+
+ *size = mUniforms[index]->elementCount();
+
+ *type = mUniforms[index]->type;
+}
+
+GLint ProgramBinary::getActiveUniformCount() const
+{
+ return mUniforms.size();
+}
+
+GLint ProgramBinary::getActiveUniformMaxLength() const
+{
+ int maxLength = 0;
+
+ unsigned int numUniforms = mUniforms.size();
+ for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
+ {
+ if (!mUniforms[uniformIndex]->name.empty())
+ {
+ int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
+ if (mUniforms[uniformIndex]->isArray())
+ {
+ length += 3; // Counting in "[0]".
+ }
+ maxLength = std::max(length, maxLength);
+ }
+ }
+
+ return maxLength;
+}
+
+void ProgramBinary::validate(InfoLog &infoLog)
+{
+ applyUniforms();
+ if (!validateSamplers(&infoLog))
+ {
+ mValidated = false;
+ }
+ else
+ {
+ mValidated = true;
+ }
+}
+
+bool ProgramBinary::validateSamplers(InfoLog *infoLog)
+{
+ // 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.
+
+ const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
+ TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+
+ for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
+ {
+ textureUnitType[i] = TEXTURE_UNKNOWN;
+ }
+
+ for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
+ {
+ if (mSamplersPS[i].active)
+ {
+ unsigned int unit = mSamplersPS[i].logicalTextureUnit;
+
+ if (unit >= maxCombinedTextureImageUnits)
+ {
+ if (infoLog)
+ {
+ infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
+ }
+
+ return false;
+ }
+
+ if (textureUnitType[unit] != TEXTURE_UNKNOWN)
+ {
+ if (mSamplersPS[i].textureType != textureUnitType[unit])
+ {
+ if (infoLog)
+ {
+ infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+ }
+
+ return false;
+ }
+ }
+ else
+ {
+ textureUnitType[unit] = mSamplersPS[i].textureType;
+ }
+ }
+ }
+
+ for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
+ {
+ if (mSamplersVS[i].active)
+ {
+ unsigned int unit = mSamplersVS[i].logicalTextureUnit;
+
+ if (unit >= maxCombinedTextureImageUnits)
+ {
+ if (infoLog)
+ {
+ infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
+ }
+
+ return false;
+ }
+
+ if (textureUnitType[unit] != TEXTURE_UNKNOWN)
+ {
+ if (mSamplersVS[i].textureType != textureUnitType[unit])
+ {
+ if (infoLog)
+ {
+ infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+ }
+
+ return false;
+ }
+ }
+ else
+ {
+ textureUnitType[unit] = mSamplersVS[i].textureType;
+ }
+ }
+ }
+
+ return true;
+}
+
+ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
+{
+}
+
+struct AttributeSorter
+{
+ AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
+ : originalIndices(semanticIndices)
+ {
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ indices[i] = i;
+ }
+
+ std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
+ }
+
+ bool operator()(int a, int b)
+ {
+ return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
+ }
+
+ int indices[MAX_VERTEX_ATTRIBS];
+ const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
+};
+
+void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
+{
+ AttributeSorter sorter(mSemanticIndex);
+
+ int oldIndices[MAX_VERTEX_ATTRIBS];
+ rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ oldIndices[i] = mSemanticIndex[i];
+ oldTranslatedAttributes[i] = attributes[i];
+ }
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ int oldIndex = sorter.indices[i];
+ sortedSemanticIndices[i] = oldIndices[oldIndex];
+ attributes[i] = oldTranslatedAttributes[oldIndex];
+ }
+}
+
+}
diff --git a/src/libGLESv2/ProgramBinary.h b/src/libGLESv2/ProgramBinary.h
new file mode 100644
index 00000000..2386c0bd
--- /dev/null
+++ b/src/libGLESv2/ProgramBinary.h
@@ -0,0 +1,174 @@
+//
+// 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.
+//
+
+// Program.h: Defines the gl::Program class. Implements GL program objects
+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
+
+#ifndef LIBGLESV2_PROGRAM_BINARY_H_
+#define LIBGLESV2_PROGRAM_BINARY_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <string>
+#include <vector>
+
+#include "common/RefCountObject.h"
+#include "angletypes.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/Uniform.h"
+#include "libGLESv2/Shader.h"
+#include "libGLESv2/Constants.h"
+
+namespace rx
+{
+class ShaderExecutable;
+class Renderer;
+struct TranslatedAttribute;
+}
+
+namespace gl
+{
+class FragmentShader;
+class VertexShader;
+class InfoLog;
+class AttributeBindings;
+struct Varying;
+
+// Struct used for correlating uniforms/elements of uniform arrays to handles
+struct UniformLocation
+{
+ UniformLocation()
+ {
+ }
+
+ UniformLocation(const std::string &name, unsigned int element, unsigned int index);
+
+ std::string name;
+ unsigned int element;
+ unsigned int index;
+};
+
+// This is the result of linking a program. It is the state that would be passed to ProgramBinary.
+class ProgramBinary : public RefCountObject
+{
+ public:
+ explicit ProgramBinary(rx::Renderer *renderer);
+ ~ProgramBinary();
+
+ rx::ShaderExecutable *getPixelExecutable();
+ rx::ShaderExecutable *getVertexExecutable();
+ rx::ShaderExecutable *getGeometryExecutable();
+
+ GLuint getAttributeLocation(const char *name);
+ int getSemanticIndex(int attributeIndex);
+
+ GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex);
+ TextureType getSamplerTextureType(SamplerType type, unsigned int samplerIndex);
+ GLint getUsedSamplerRange(SamplerType type);
+ bool usesPointSize() const;
+ bool usesPointSpriteEmulation() const;
+ bool usesGeometryShader() const;
+
+ GLint getUniformLocation(std::string name);
+ bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
+ bool setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
+ bool setUniform3fv(GLint location, GLsizei count, const GLfloat *v);
+ bool setUniform4fv(GLint location, GLsizei count, const GLfloat *v);
+ bool setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value);
+ bool setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value);
+ bool setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value);
+ bool setUniform1iv(GLint location, GLsizei count, const GLint *v);
+ bool setUniform2iv(GLint location, GLsizei count, const GLint *v);
+ bool setUniform3iv(GLint location, GLsizei count, const GLint *v);
+ bool setUniform4iv(GLint location, GLsizei count, const GLint *v);
+
+ bool getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params);
+ bool getUniformiv(GLint location, GLsizei *bufSize, GLint *params);
+
+ void dirtyAllUniforms();
+ void applyUniforms();
+
+ bool load(InfoLog &infoLog, const void *binary, GLsizei length);
+ bool save(void* binary, GLsizei bufSize, GLsizei *length);
+ GLint getLength();
+
+ bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
+ void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
+
+ void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const;
+ GLint getActiveAttributeCount() const;
+ GLint getActiveAttributeMaxLength() const;
+
+ void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const;
+ GLint getActiveUniformCount() const;
+ GLint getActiveUniformMaxLength() const;
+
+ void validate(InfoLog &infoLog);
+ bool validateSamplers(InfoLog *infoLog);
+ bool isValidated() const;
+
+ unsigned int getSerial() const;
+
+ void sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const;
+
+ static std::string decorateAttribute(const std::string &name); // Prepend an underscore
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProgramBinary);
+
+ int packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader);
+ bool linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
+ std::string& pixelHLSL, std::string& vertexHLSL,
+ FragmentShader *fragmentShader, VertexShader *vertexShader);
+
+ bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
+
+ bool linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms);
+ bool defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog);
+
+ std::string generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const;
+ std::string generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const;
+
+ rx::Renderer *const mRenderer;
+
+ rx::ShaderExecutable *mPixelExecutable;
+ rx::ShaderExecutable *mVertexExecutable;
+ rx::ShaderExecutable *mGeometryExecutable;
+
+ Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS];
+ int mSemanticIndex[MAX_VERTEX_ATTRIBS];
+
+ struct Sampler
+ {
+ Sampler();
+
+ bool active;
+ GLint logicalTextureUnit;
+ TextureType textureType;
+ };
+
+ Sampler mSamplersPS[MAX_TEXTURE_IMAGE_UNITS];
+ Sampler mSamplersVS[IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
+ GLuint mUsedVertexSamplerRange;
+ GLuint mUsedPixelSamplerRange;
+ bool mUsesPointSize;
+
+ UniformArray mUniforms;
+ typedef std::vector<UniformLocation> UniformIndex;
+ UniformIndex mUniformIndex;
+
+ bool mValidated;
+
+ const unsigned int mSerial;
+
+ static unsigned int issueSerial();
+ static unsigned int mCurrentSerial;
+};
+}
+
+#endif // LIBGLESV2_PROGRAM_BINARY_H_
diff --git a/src/libGLESv2/Query.cpp b/src/libGLESv2/Query.cpp
new file mode 100644
index 00000000..bd987954
--- /dev/null
+++ b/src/libGLESv2/Query.cpp
@@ -0,0 +1,52 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Query.cpp: Implements the gl::Query class
+
+#include "libGLESv2/Query.h"
+#include "libGLESv2/renderer/QueryImpl.h"
+#include "libGLESv2/renderer/Renderer.h"
+
+namespace gl
+{
+
+Query::Query(rx::Renderer *renderer, GLenum type, GLuint id) : RefCountObject(id)
+{
+ mQuery = renderer->createQuery(type);
+}
+
+Query::~Query()
+{
+ delete mQuery;
+}
+
+void Query::begin()
+{
+ mQuery->begin();
+}
+
+void Query::end()
+{
+ mQuery->end();
+}
+
+GLuint Query::getResult()
+{
+ return mQuery->getResult();
+}
+
+GLboolean Query::isResultAvailable()
+{
+ return mQuery->isResultAvailable();
+}
+
+GLenum Query::getType() const
+{
+ return mQuery->getType();
+}
+
+}
diff --git a/src/libGLESv2/Query.h b/src/libGLESv2/Query.h
new file mode 100644
index 00000000..e9b95b72
--- /dev/null
+++ b/src/libGLESv2/Query.h
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Query.h: Defines the gl::Query class
+
+#ifndef LIBGLESV2_QUERY_H_
+#define LIBGLESV2_QUERY_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "common/angleutils.h"
+#include "common/RefCountObject.h"
+
+namespace rx
+{
+class Renderer;
+class QueryImpl;
+}
+
+namespace gl
+{
+
+class Query : public RefCountObject
+{
+ public:
+ Query(rx::Renderer *renderer, GLenum type, GLuint id);
+ virtual ~Query();
+
+ void begin();
+ void end();
+
+ GLuint getResult();
+ GLboolean isResultAvailable();
+
+ GLenum getType() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Query);
+
+ rx::QueryImpl *mQuery;
+};
+
+}
+
+#endif // LIBGLESV2_QUERY_H_
diff --git a/src/libGLESv2/Renderbuffer.cpp b/src/libGLESv2/Renderbuffer.cpp
new file mode 100644
index 00000000..12751374
--- /dev/null
+++ b/src/libGLESv2/Renderbuffer.cpp
@@ -0,0 +1,485 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderbuffer.cpp: the gl::Renderbuffer class and its derived classes
+// Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108.
+
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/renderer/RenderTarget.h"
+
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/utilities.h"
+
+namespace gl
+{
+unsigned int RenderbufferStorage::mCurrentSerial = 1;
+
+RenderbufferInterface::RenderbufferInterface()
+{
+}
+
+// The default case for classes inherited from RenderbufferInterface is not to
+// need to do anything upon the reference count to the parent Renderbuffer incrementing
+// or decrementing.
+void RenderbufferInterface::addProxyRef(const Renderbuffer *proxy)
+{
+}
+
+void RenderbufferInterface::releaseProxy(const Renderbuffer *proxy)
+{
+}
+
+GLuint RenderbufferInterface::getRedSize() const
+{
+ return gl::GetRedSize(getActualFormat());
+}
+
+GLuint RenderbufferInterface::getGreenSize() const
+{
+ return gl::GetGreenSize(getActualFormat());
+}
+
+GLuint RenderbufferInterface::getBlueSize() const
+{
+ return gl::GetBlueSize(getActualFormat());
+}
+
+GLuint RenderbufferInterface::getAlphaSize() const
+{
+ return gl::GetAlphaSize(getActualFormat());
+}
+
+GLuint RenderbufferInterface::getDepthSize() const
+{
+ return gl::GetDepthSize(getActualFormat());
+}
+
+GLuint RenderbufferInterface::getStencilSize() const
+{
+ return gl::GetStencilSize(getActualFormat());
+}
+
+///// RenderbufferTexture2D Implementation ////////
+
+RenderbufferTexture2D::RenderbufferTexture2D(Texture2D *texture, GLenum target) : mTarget(target)
+{
+ mTexture2D.set(texture);
+}
+
+RenderbufferTexture2D::~RenderbufferTexture2D()
+{
+ mTexture2D.set(NULL);
+}
+
+// Textures need to maintain their own reference count for references via
+// Renderbuffers acting as proxies. Here, we notify the texture of a reference.
+void RenderbufferTexture2D::addProxyRef(const Renderbuffer *proxy)
+{
+ mTexture2D->addProxyRef(proxy);
+}
+
+void RenderbufferTexture2D::releaseProxy(const Renderbuffer *proxy)
+{
+ mTexture2D->releaseProxy(proxy);
+}
+
+rx::RenderTarget *RenderbufferTexture2D::getRenderTarget()
+{
+ return mTexture2D->getRenderTarget(mTarget);
+}
+
+rx::RenderTarget *RenderbufferTexture2D::getDepthStencil()
+{
+ return mTexture2D->getDepthStencil(mTarget);
+}
+
+GLsizei RenderbufferTexture2D::getWidth() const
+{
+ return mTexture2D->getWidth(0);
+}
+
+GLsizei RenderbufferTexture2D::getHeight() const
+{
+ return mTexture2D->getHeight(0);
+}
+
+GLenum RenderbufferTexture2D::getInternalFormat() const
+{
+ return mTexture2D->getInternalFormat(0);
+}
+
+GLenum RenderbufferTexture2D::getActualFormat() const
+{
+ return mTexture2D->getActualFormat(0);
+}
+
+GLsizei RenderbufferTexture2D::getSamples() const
+{
+ return 0;
+}
+
+unsigned int RenderbufferTexture2D::getSerial() const
+{
+ return mTexture2D->getRenderTargetSerial(mTarget);
+}
+
+///// RenderbufferTextureCubeMap Implementation ////////
+
+RenderbufferTextureCubeMap::RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target) : mTarget(target)
+{
+ mTextureCubeMap.set(texture);
+}
+
+RenderbufferTextureCubeMap::~RenderbufferTextureCubeMap()
+{
+ mTextureCubeMap.set(NULL);
+}
+
+// Textures need to maintain their own reference count for references via
+// Renderbuffers acting as proxies. Here, we notify the texture of a reference.
+void RenderbufferTextureCubeMap::addProxyRef(const Renderbuffer *proxy)
+{
+ mTextureCubeMap->addProxyRef(proxy);
+}
+
+void RenderbufferTextureCubeMap::releaseProxy(const Renderbuffer *proxy)
+{
+ mTextureCubeMap->releaseProxy(proxy);
+}
+
+rx::RenderTarget *RenderbufferTextureCubeMap::getRenderTarget()
+{
+ return mTextureCubeMap->getRenderTarget(mTarget);
+}
+
+rx::RenderTarget *RenderbufferTextureCubeMap::getDepthStencil()
+{
+ return NULL;
+}
+
+GLsizei RenderbufferTextureCubeMap::getWidth() const
+{
+ return mTextureCubeMap->getWidth(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
+}
+
+GLsizei RenderbufferTextureCubeMap::getHeight() const
+{
+ return mTextureCubeMap->getHeight(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
+}
+
+GLenum RenderbufferTextureCubeMap::getInternalFormat() const
+{
+ return mTextureCubeMap->getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
+}
+
+GLenum RenderbufferTextureCubeMap::getActualFormat() const
+{
+ return mTextureCubeMap->getActualFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
+}
+
+GLsizei RenderbufferTextureCubeMap::getSamples() const
+{
+ return 0;
+}
+
+unsigned int RenderbufferTextureCubeMap::getSerial() const
+{
+ return mTextureCubeMap->getRenderTargetSerial(mTarget);
+}
+
+////// Renderbuffer Implementation //////
+
+Renderbuffer::Renderbuffer(rx::Renderer *renderer, GLuint id, RenderbufferInterface *instance) : RefCountObject(id)
+{
+ ASSERT(instance != NULL);
+ mInstance = instance;
+}
+
+Renderbuffer::~Renderbuffer()
+{
+ delete mInstance;
+}
+
+// The RenderbufferInterface contained in this Renderbuffer may need to maintain
+// its own reference count, so we pass it on here.
+void Renderbuffer::addRef() const
+{
+ mInstance->addProxyRef(this);
+
+ RefCountObject::addRef();
+}
+
+void Renderbuffer::release() const
+{
+ mInstance->releaseProxy(this);
+
+ RefCountObject::release();
+}
+
+rx::RenderTarget *Renderbuffer::getRenderTarget()
+{
+ return mInstance->getRenderTarget();
+}
+
+rx::RenderTarget *Renderbuffer::getDepthStencil()
+{
+ return mInstance->getDepthStencil();
+}
+
+GLsizei Renderbuffer::getWidth() const
+{
+ return mInstance->getWidth();
+}
+
+GLsizei Renderbuffer::getHeight() const
+{
+ return mInstance->getHeight();
+}
+
+GLenum Renderbuffer::getInternalFormat() const
+{
+ return mInstance->getInternalFormat();
+}
+
+GLenum Renderbuffer::getActualFormat() const
+{
+ return mInstance->getActualFormat();
+}
+
+GLuint Renderbuffer::getRedSize() const
+{
+ return mInstance->getRedSize();
+}
+
+GLuint Renderbuffer::getGreenSize() const
+{
+ return mInstance->getGreenSize();
+}
+
+GLuint Renderbuffer::getBlueSize() const
+{
+ return mInstance->getBlueSize();
+}
+
+GLuint Renderbuffer::getAlphaSize() const
+{
+ return mInstance->getAlphaSize();
+}
+
+GLuint Renderbuffer::getDepthSize() const
+{
+ return mInstance->getDepthSize();
+}
+
+GLuint Renderbuffer::getStencilSize() const
+{
+ return mInstance->getStencilSize();
+}
+
+GLsizei Renderbuffer::getSamples() const
+{
+ return mInstance->getSamples();
+}
+
+unsigned int Renderbuffer::getSerial() const
+{
+ return mInstance->getSerial();
+}
+
+void Renderbuffer::setStorage(RenderbufferStorage *newStorage)
+{
+ ASSERT(newStorage != NULL);
+
+ delete mInstance;
+ mInstance = newStorage;
+}
+
+RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerial())
+{
+ mWidth = 0;
+ mHeight = 0;
+ mInternalFormat = GL_RGBA4;
+ mActualFormat = GL_RGBA8_OES;
+ mSamples = 0;
+}
+
+RenderbufferStorage::~RenderbufferStorage()
+{
+}
+
+rx::RenderTarget *RenderbufferStorage::getRenderTarget()
+{
+ return NULL;
+}
+
+rx::RenderTarget *RenderbufferStorage::getDepthStencil()
+{
+ return NULL;
+}
+
+GLsizei RenderbufferStorage::getWidth() const
+{
+ return mWidth;
+}
+
+GLsizei RenderbufferStorage::getHeight() const
+{
+ return mHeight;
+}
+
+GLenum RenderbufferStorage::getInternalFormat() const
+{
+ return mInternalFormat;
+}
+
+GLenum RenderbufferStorage::getActualFormat() const
+{
+ return mActualFormat;
+}
+
+GLsizei RenderbufferStorage::getSamples() const
+{
+ return mSamples;
+}
+
+unsigned int RenderbufferStorage::getSerial() const
+{
+ return mSerial;
+}
+
+unsigned int RenderbufferStorage::issueSerial()
+{
+ return mCurrentSerial++;
+}
+
+unsigned int RenderbufferStorage::issueCubeSerials()
+{
+ unsigned int firstSerial = mCurrentSerial;
+ mCurrentSerial += 6;
+ return firstSerial;
+}
+
+Colorbuffer::Colorbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain)
+{
+ mRenderTarget = renderer->createRenderTarget(swapChain, false);
+
+ if (mRenderTarget)
+ {
+ mWidth = mRenderTarget->getWidth();
+ mHeight = mRenderTarget->getHeight();
+ mInternalFormat = mRenderTarget->getInternalFormat();
+ mActualFormat = mRenderTarget->getActualFormat();
+ mSamples = mRenderTarget->getSamples();
+ }
+}
+
+Colorbuffer::Colorbuffer(rx::Renderer *renderer, int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL)
+{
+ mRenderTarget = renderer->createRenderTarget(width, height, format, samples, false);
+
+ if (mRenderTarget)
+ {
+ mWidth = width;
+ mHeight = height;
+ mInternalFormat = format;
+ mActualFormat = mRenderTarget->getActualFormat();
+ mSamples = mRenderTarget->getSamples();
+ }
+}
+
+Colorbuffer::~Colorbuffer()
+{
+ if (mRenderTarget)
+ {
+ delete mRenderTarget;
+ }
+}
+
+rx::RenderTarget *Colorbuffer::getRenderTarget()
+{
+ if (mRenderTarget)
+ {
+ return mRenderTarget;
+ }
+
+ return NULL;
+}
+
+DepthStencilbuffer::DepthStencilbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain)
+{
+ mDepthStencil = renderer->createRenderTarget(swapChain, true);
+ if (mDepthStencil)
+ {
+ mWidth = mDepthStencil->getWidth();
+ mHeight = mDepthStencil->getHeight();
+ mInternalFormat = mDepthStencil->getInternalFormat();
+ mSamples = mDepthStencil->getSamples();
+ mActualFormat = mDepthStencil->getActualFormat();
+ }
+}
+
+DepthStencilbuffer::DepthStencilbuffer(rx::Renderer *renderer, int width, int height, GLsizei samples)
+{
+
+ mDepthStencil = renderer->createRenderTarget(width, height, GL_DEPTH24_STENCIL8_OES, samples, true);
+
+ mWidth = mDepthStencil->getWidth();
+ mHeight = mDepthStencil->getHeight();
+ mInternalFormat = GL_DEPTH24_STENCIL8_OES;
+ mActualFormat = mDepthStencil->getActualFormat();
+ mSamples = mDepthStencil->getSamples();
+}
+
+DepthStencilbuffer::~DepthStencilbuffer()
+{
+ if (mDepthStencil)
+ {
+ delete mDepthStencil;
+ }
+}
+
+rx::RenderTarget *DepthStencilbuffer::getDepthStencil()
+{
+ if (mDepthStencil)
+ {
+ return mDepthStencil;
+ }
+
+ return NULL;
+}
+
+Depthbuffer::Depthbuffer(rx::Renderer *renderer, int width, int height, GLsizei samples) : DepthStencilbuffer(renderer, width, height, samples)
+{
+ if (mDepthStencil)
+ {
+ mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
+ }
+}
+
+Depthbuffer::~Depthbuffer()
+{
+}
+
+Stencilbuffer::Stencilbuffer(rx::Renderer *renderer, int width, int height, GLsizei samples) : DepthStencilbuffer(renderer, width, height, samples)
+{
+ if (mDepthStencil)
+ {
+ mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
+ }
+}
+
+Stencilbuffer::~Stencilbuffer()
+{
+}
+
+}
diff --git a/src/libGLESv2/Renderbuffer.h b/src/libGLESv2/Renderbuffer.h
new file mode 100644
index 00000000..eca2f3a7
--- /dev/null
+++ b/src/libGLESv2/Renderbuffer.h
@@ -0,0 +1,261 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderbuffer.h: Defines the wrapper class gl::Renderbuffer, as well as the
+// class hierarchy used to store its contents: RenderbufferStorage, Colorbuffer,
+// DepthStencilbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108.
+
+#ifndef LIBGLESV2_RENDERBUFFER_H_
+#define LIBGLESV2_RENDERBUFFER_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "common/angleutils.h"
+#include "common/RefCountObject.h"
+
+namespace rx
+{
+class Renderer;
+class SwapChain;
+class RenderTarget;
+}
+
+namespace gl
+{
+class Texture2D;
+class TextureCubeMap;
+class Renderbuffer;
+class Colorbuffer;
+class DepthStencilbuffer;
+
+class RenderbufferInterface
+{
+ public:
+ RenderbufferInterface();
+
+ virtual ~RenderbufferInterface() {};
+
+ virtual void addProxyRef(const Renderbuffer *proxy);
+ virtual void releaseProxy(const Renderbuffer *proxy);
+
+ virtual rx::RenderTarget *getRenderTarget() = 0;
+ virtual rx::RenderTarget *getDepthStencil() = 0;
+
+ virtual GLsizei getWidth() const = 0;
+ virtual GLsizei getHeight() const = 0;
+ virtual GLenum getInternalFormat() const = 0;
+ virtual GLenum getActualFormat() const = 0;
+ virtual GLsizei getSamples() const = 0;
+
+ GLuint getRedSize() const;
+ GLuint getGreenSize() const;
+ GLuint getBlueSize() const;
+ GLuint getAlphaSize() const;
+ GLuint getDepthSize() const;
+ GLuint getStencilSize() const;
+
+ virtual unsigned int getSerial() const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderbufferInterface);
+};
+
+class RenderbufferTexture2D : public RenderbufferInterface
+{
+ public:
+ RenderbufferTexture2D(Texture2D *texture, GLenum target);
+
+ virtual ~RenderbufferTexture2D();
+
+ void addProxyRef(const Renderbuffer *proxy);
+ void releaseProxy(const Renderbuffer *proxy);
+
+ rx::RenderTarget *getRenderTarget();
+ rx::RenderTarget *getDepthStencil();
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getInternalFormat() const;
+ virtual GLenum getActualFormat() const;
+ virtual GLsizei getSamples() const;
+
+ virtual unsigned int getSerial() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderbufferTexture2D);
+
+ BindingPointer <Texture2D> mTexture2D;
+ GLenum mTarget;
+};
+
+class RenderbufferTextureCubeMap : public RenderbufferInterface
+{
+ public:
+ RenderbufferTextureCubeMap(TextureCubeMap *texture, GLenum target);
+
+ virtual ~RenderbufferTextureCubeMap();
+
+ void addProxyRef(const Renderbuffer *proxy);
+ void releaseProxy(const Renderbuffer *proxy);
+
+ rx::RenderTarget *getRenderTarget();
+ rx::RenderTarget *getDepthStencil();
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getInternalFormat() const;
+ virtual GLenum getActualFormat() const;
+ virtual GLsizei getSamples() const;
+
+ virtual unsigned int getSerial() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderbufferTextureCubeMap);
+
+ BindingPointer <TextureCubeMap> mTextureCubeMap;
+ GLenum mTarget;
+};
+
+// A class derived from RenderbufferStorage is created whenever glRenderbufferStorage
+// is called. The specific concrete type depends on whether the internal format is
+// colour depth, stencil or packed depth/stencil.
+class RenderbufferStorage : public RenderbufferInterface
+{
+ public:
+ RenderbufferStorage();
+
+ virtual ~RenderbufferStorage() = 0;
+
+ virtual rx::RenderTarget *getRenderTarget();
+ virtual rx::RenderTarget *getDepthStencil();
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getInternalFormat() const;
+ virtual GLenum getActualFormat() const;
+ virtual GLsizei getSamples() const;
+
+ virtual unsigned int getSerial() const;
+
+ static unsigned int issueSerial();
+ static unsigned int issueCubeSerials();
+
+ protected:
+ GLsizei mWidth;
+ GLsizei mHeight;
+ GLenum mInternalFormat;
+ GLenum mActualFormat;
+ GLsizei mSamples;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderbufferStorage);
+
+ const unsigned int mSerial;
+
+ static unsigned int mCurrentSerial;
+};
+
+// Renderbuffer implements the GL renderbuffer object.
+// It's only a proxy for a RenderbufferInterface instance; the internal object
+// can change whenever glRenderbufferStorage is called.
+class Renderbuffer : public RefCountObject
+{
+ public:
+ Renderbuffer(rx::Renderer *renderer, GLuint id, RenderbufferInterface *storage);
+
+ virtual ~Renderbuffer();
+
+ // These functions from RefCountObject are overloaded here because
+ // Textures need to maintain their own count of references to them via
+ // Renderbuffers/RenderbufferTextures. These functions invoke those
+ // reference counting functions on the RenderbufferInterface.
+ void addRef() const;
+ void release() const;
+
+ rx::RenderTarget *getRenderTarget();
+ rx::RenderTarget *getDepthStencil();
+
+ GLsizei getWidth() const;
+ GLsizei getHeight() const;
+ GLenum getInternalFormat() const;
+ GLenum getActualFormat() const;
+ GLuint getRedSize() const;
+ GLuint getGreenSize() const;
+ GLuint getBlueSize() const;
+ GLuint getAlphaSize() const;
+ GLuint getDepthSize() const;
+ GLuint getStencilSize() const;
+ GLsizei getSamples() const;
+
+ unsigned int getSerial() const;
+
+ void setStorage(RenderbufferStorage *newStorage);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Renderbuffer);
+
+ RenderbufferInterface *mInstance;
+};
+
+class Colorbuffer : public RenderbufferStorage
+{
+ public:
+ Colorbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain);
+ Colorbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples);
+
+ virtual ~Colorbuffer();
+
+ virtual rx::RenderTarget *getRenderTarget();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Colorbuffer);
+
+ rx::RenderTarget *mRenderTarget;
+};
+
+class DepthStencilbuffer : public RenderbufferStorage
+{
+ public:
+ DepthStencilbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain);
+ DepthStencilbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLsizei samples);
+
+ ~DepthStencilbuffer();
+
+ virtual rx::RenderTarget *getDepthStencil();
+
+ protected:
+ rx::RenderTarget *mDepthStencil;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DepthStencilbuffer);
+};
+
+class Depthbuffer : public DepthStencilbuffer
+{
+ public:
+ Depthbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLsizei samples);
+
+ virtual ~Depthbuffer();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Depthbuffer);
+};
+
+class Stencilbuffer : public DepthStencilbuffer
+{
+ public:
+ Stencilbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLsizei samples);
+
+ virtual ~Stencilbuffer();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Stencilbuffer);
+};
+}
+
+#endif // LIBGLESV2_RENDERBUFFER_H_
diff --git a/src/libGLESv2/ResourceManager.cpp b/src/libGLESv2/ResourceManager.cpp
new file mode 100644
index 00000000..58dd44fd
--- /dev/null
+++ b/src/libGLESv2/ResourceManager.cpp
@@ -0,0 +1,322 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// ResourceManager.cpp: Implements the gl::ResourceManager class, which tracks and
+// retrieves objects which may be shared by multiple Contexts.
+
+#include "libGLESv2/ResourceManager.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/Shader.h"
+#include "libGLESv2/Texture.h"
+
+namespace gl
+{
+ResourceManager::ResourceManager(rx::Renderer *renderer)
+{
+ mRefCount = 1;
+ mRenderer = renderer;
+}
+
+ResourceManager::~ResourceManager()
+{
+ while (!mBufferMap.empty())
+ {
+ deleteBuffer(mBufferMap.begin()->first);
+ }
+
+ while (!mProgramMap.empty())
+ {
+ deleteProgram(mProgramMap.begin()->first);
+ }
+
+ while (!mShaderMap.empty())
+ {
+ deleteShader(mShaderMap.begin()->first);
+ }
+
+ while (!mRenderbufferMap.empty())
+ {
+ deleteRenderbuffer(mRenderbufferMap.begin()->first);
+ }
+
+ while (!mTextureMap.empty())
+ {
+ deleteTexture(mTextureMap.begin()->first);
+ }
+}
+
+void ResourceManager::addRef()
+{
+ mRefCount++;
+}
+
+void ResourceManager::release()
+{
+ if (--mRefCount == 0)
+ {
+ delete this;
+ }
+}
+
+// Returns an unused buffer name
+GLuint ResourceManager::createBuffer()
+{
+ GLuint handle = mBufferHandleAllocator.allocate();
+
+ mBufferMap[handle] = NULL;
+
+ return handle;
+}
+
+// Returns an unused shader/program name
+GLuint ResourceManager::createShader(GLenum type)
+{
+ GLuint handle = mProgramShaderHandleAllocator.allocate();
+
+ if (type == GL_VERTEX_SHADER)
+ {
+ mShaderMap[handle] = new VertexShader(this, mRenderer, handle);
+ }
+ else if (type == GL_FRAGMENT_SHADER)
+ {
+ mShaderMap[handle] = new FragmentShader(this, mRenderer, handle);
+ }
+ else UNREACHABLE();
+
+ return handle;
+}
+
+// Returns an unused program/shader name
+GLuint ResourceManager::createProgram()
+{
+ GLuint handle = mProgramShaderHandleAllocator.allocate();
+
+ mProgramMap[handle] = new Program(mRenderer, this, handle);
+
+ return handle;
+}
+
+// Returns an unused texture name
+GLuint ResourceManager::createTexture()
+{
+ GLuint handle = mTextureHandleAllocator.allocate();
+
+ mTextureMap[handle] = NULL;
+
+ return handle;
+}
+
+// Returns an unused renderbuffer name
+GLuint ResourceManager::createRenderbuffer()
+{
+ GLuint handle = mRenderbufferHandleAllocator.allocate();
+
+ mRenderbufferMap[handle] = NULL;
+
+ return handle;
+}
+
+void ResourceManager::deleteBuffer(GLuint buffer)
+{
+ BufferMap::iterator bufferObject = mBufferMap.find(buffer);
+
+ if (bufferObject != mBufferMap.end())
+ {
+ mBufferHandleAllocator.release(bufferObject->first);
+ if (bufferObject->second) bufferObject->second->release();
+ mBufferMap.erase(bufferObject);
+ }
+}
+
+void ResourceManager::deleteShader(GLuint shader)
+{
+ ShaderMap::iterator shaderObject = mShaderMap.find(shader);
+
+ if (shaderObject != mShaderMap.end())
+ {
+ if (shaderObject->second->getRefCount() == 0)
+ {
+ mProgramShaderHandleAllocator.release(shaderObject->first);
+ delete shaderObject->second;
+ mShaderMap.erase(shaderObject);
+ }
+ else
+ {
+ shaderObject->second->flagForDeletion();
+ }
+ }
+}
+
+void ResourceManager::deleteProgram(GLuint program)
+{
+ ProgramMap::iterator programObject = mProgramMap.find(program);
+
+ if (programObject != mProgramMap.end())
+ {
+ if (programObject->second->getRefCount() == 0)
+ {
+ mProgramShaderHandleAllocator.release(programObject->first);
+ delete programObject->second;
+ mProgramMap.erase(programObject);
+ }
+ else
+ {
+ programObject->second->flagForDeletion();
+ }
+ }
+}
+
+void ResourceManager::deleteTexture(GLuint texture)
+{
+ TextureMap::iterator textureObject = mTextureMap.find(texture);
+
+ if (textureObject != mTextureMap.end())
+ {
+ mTextureHandleAllocator.release(textureObject->first);
+ if (textureObject->second) textureObject->second->release();
+ mTextureMap.erase(textureObject);
+ }
+}
+
+void ResourceManager::deleteRenderbuffer(GLuint renderbuffer)
+{
+ RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer);
+
+ if (renderbufferObject != mRenderbufferMap.end())
+ {
+ mRenderbufferHandleAllocator.release(renderbufferObject->first);
+ if (renderbufferObject->second) renderbufferObject->second->release();
+ mRenderbufferMap.erase(renderbufferObject);
+ }
+}
+
+Buffer *ResourceManager::getBuffer(unsigned int handle)
+{
+ BufferMap::iterator buffer = mBufferMap.find(handle);
+
+ if (buffer == mBufferMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return buffer->second;
+ }
+}
+
+Shader *ResourceManager::getShader(unsigned int handle)
+{
+ ShaderMap::iterator shader = mShaderMap.find(handle);
+
+ if (shader == mShaderMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return shader->second;
+ }
+}
+
+Texture *ResourceManager::getTexture(unsigned int handle)
+{
+ if (handle == 0) return NULL;
+
+ TextureMap::iterator texture = mTextureMap.find(handle);
+
+ if (texture == mTextureMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return texture->second;
+ }
+}
+
+Program *ResourceManager::getProgram(unsigned int handle)
+{
+ ProgramMap::iterator program = mProgramMap.find(handle);
+
+ if (program == mProgramMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return program->second;
+ }
+}
+
+Renderbuffer *ResourceManager::getRenderbuffer(unsigned int handle)
+{
+ RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle);
+
+ if (renderbuffer == mRenderbufferMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return renderbuffer->second;
+ }
+}
+
+void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer)
+{
+ mRenderbufferMap[handle] = buffer;
+}
+
+void ResourceManager::checkBufferAllocation(unsigned int buffer)
+{
+ if (buffer != 0 && !getBuffer(buffer))
+ {
+ Buffer *bufferObject = new Buffer(mRenderer, buffer);
+ mBufferMap[buffer] = bufferObject;
+ bufferObject->addRef();
+ }
+}
+
+void ResourceManager::checkTextureAllocation(GLuint texture, TextureType type)
+{
+ if (!getTexture(texture) && texture != 0)
+ {
+ Texture *textureObject;
+
+ if (type == TEXTURE_2D)
+ {
+ textureObject = new Texture2D(mRenderer, texture);
+ }
+ else if (type == TEXTURE_CUBE)
+ {
+ textureObject = new TextureCubeMap(mRenderer, texture);
+ }
+ else
+ {
+ UNREACHABLE();
+ return;
+ }
+
+ mTextureMap[texture] = textureObject;
+ textureObject->addRef();
+ }
+}
+
+void ResourceManager::checkRenderbufferAllocation(GLuint renderbuffer)
+{
+ if (renderbuffer != 0 && !getRenderbuffer(renderbuffer))
+ {
+ Renderbuffer *renderbufferObject = new Renderbuffer(mRenderer, renderbuffer, new Colorbuffer(mRenderer, 0, 0, GL_RGBA4, 0));
+ mRenderbufferMap[renderbuffer] = renderbufferObject;
+ renderbufferObject->addRef();
+ }
+}
+
+}
diff --git a/src/libGLESv2/ResourceManager.h b/src/libGLESv2/ResourceManager.h
new file mode 100644
index 00000000..e99c77c3
--- /dev/null
+++ b/src/libGLESv2/ResourceManager.h
@@ -0,0 +1,108 @@
+//
+// 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.
+//
+
+// ResourceManager.h : Defines the ResourceManager class, which tracks objects
+// shared by multiple GL contexts.
+
+#ifndef LIBGLESV2_RESOURCEMANAGER_H_
+#define LIBGLESV2_RESOURCEMANAGER_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#ifdef _MSC_VER
+#include <hash_map>
+#else
+#include <unordered_map>
+#endif
+
+#include "common/angleutils.h"
+#include "libGLESv2/angletypes.h"
+#include "libGLESv2/HandleAllocator.h"
+
+namespace rx
+{
+class Renderer;
+}
+
+namespace gl
+{
+class Buffer;
+class Shader;
+class Program;
+class Texture;
+class Renderbuffer;
+
+class ResourceManager
+{
+ public:
+ explicit ResourceManager(rx::Renderer *renderer);
+ ~ResourceManager();
+
+ void addRef();
+ void release();
+
+ GLuint createBuffer();
+ GLuint createShader(GLenum type);
+ GLuint createProgram();
+ GLuint createTexture();
+ GLuint createRenderbuffer();
+
+ void deleteBuffer(GLuint buffer);
+ void deleteShader(GLuint shader);
+ void deleteProgram(GLuint program);
+ void deleteTexture(GLuint texture);
+ void deleteRenderbuffer(GLuint renderbuffer);
+
+ Buffer *getBuffer(GLuint handle);
+ Shader *getShader(GLuint handle);
+ Program *getProgram(GLuint handle);
+ Texture *getTexture(GLuint handle);
+ Renderbuffer *getRenderbuffer(GLuint handle);
+
+ void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer);
+
+ void checkBufferAllocation(unsigned int buffer);
+ void checkTextureAllocation(GLuint texture, TextureType type);
+ void checkRenderbufferAllocation(GLuint renderbuffer);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResourceManager);
+
+ std::size_t mRefCount;
+ rx::Renderer *mRenderer;
+
+#ifndef HASH_MAP
+# ifdef _MSC_VER
+# define HASH_MAP stdext::hash_map
+# else
+# define HASH_MAP std::unordered_map
+# endif
+#endif
+
+ typedef HASH_MAP<GLuint, Buffer*> BufferMap;
+ BufferMap mBufferMap;
+ HandleAllocator mBufferHandleAllocator;
+
+ typedef HASH_MAP<GLuint, Shader*> ShaderMap;
+ ShaderMap mShaderMap;
+
+ typedef HASH_MAP<GLuint, Program*> ProgramMap;
+ ProgramMap mProgramMap;
+ HandleAllocator mProgramShaderHandleAllocator;
+
+ typedef HASH_MAP<GLuint, Texture*> TextureMap;
+ TextureMap mTextureMap;
+ HandleAllocator mTextureHandleAllocator;
+
+ typedef HASH_MAP<GLuint, Renderbuffer*> RenderbufferMap;
+ RenderbufferMap mRenderbufferMap;
+ HandleAllocator mRenderbufferHandleAllocator;
+};
+
+}
+
+#endif // LIBGLESV2_RESOURCEMANAGER_H_
diff --git a/src/libGLESv2/Shader.cpp b/src/libGLESv2/Shader.cpp
new file mode 100644
index 00000000..7dfdd0ba
--- /dev/null
+++ b/src/libGLESv2/Shader.cpp
@@ -0,0 +1,622 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Shader.cpp: Implements the gl::Shader class and its derived classes
+// VertexShader and FragmentShader. Implements GL shader objects and related
+// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
+
+#include "libGLESv2/Shader.h"
+
+#include "GLSLANG/ShaderLang.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/Constants.h"
+#include "libGLESv2/ResourceManager.h"
+
+namespace gl
+{
+void *Shader::mFragmentCompiler = NULL;
+void *Shader::mVertexCompiler = NULL;
+
+Shader::Shader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle)
+ : mHandle(handle), mRenderer(renderer), mResourceManager(manager)
+{
+ mSource = NULL;
+ mHlsl = NULL;
+ mInfoLog = NULL;
+
+ uncompile();
+ initializeCompiler();
+
+ mRefCount = 0;
+ mDeleteStatus = false;
+}
+
+Shader::~Shader()
+{
+ delete[] mSource;
+ delete[] mHlsl;
+ delete[] mInfoLog;
+}
+
+GLuint Shader::getHandle() const
+{
+ return mHandle;
+}
+
+void Shader::setSource(GLsizei count, const char **string, const GLint *length)
+{
+ delete[] mSource;
+ int totalLength = 0;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (length && length[i] >= 0)
+ {
+ totalLength += length[i];
+ }
+ else
+ {
+ totalLength += (int)strlen(string[i]);
+ }
+ }
+
+ mSource = new char[totalLength + 1];
+ char *code = mSource;
+
+ for (int i = 0; i < count; i++)
+ {
+ int stringLength;
+
+ if (length && length[i] >= 0)
+ {
+ stringLength = length[i];
+ }
+ else
+ {
+ stringLength = (int)strlen(string[i]);
+ }
+
+ strncpy(code, string[i], stringLength);
+ code += stringLength;
+ }
+
+ mSource[totalLength] = '\0';
+}
+
+int Shader::getInfoLogLength() const
+{
+ if (!mInfoLog)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(mInfoLog) + 1;
+ }
+}
+
+void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+ int index = 0;
+
+ if (bufSize > 0)
+ {
+ if (mInfoLog)
+ {
+ index = std::min(bufSize - 1, (int)strlen(mInfoLog));
+ memcpy(infoLog, mInfoLog, index);
+ }
+
+ infoLog[index] = '\0';
+ }
+
+ if (length)
+ {
+ *length = index;
+ }
+}
+
+int Shader::getSourceLength() const
+{
+ if (!mSource)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(mSource) + 1;
+ }
+}
+
+int Shader::getTranslatedSourceLength() const
+{
+ if (!mHlsl)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(mHlsl) + 1;
+ }
+}
+
+void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer)
+{
+ int index = 0;
+
+ if (bufSize > 0)
+ {
+ if (source)
+ {
+ index = std::min(bufSize - 1, (int)strlen(source));
+ memcpy(buffer, source, index);
+ }
+
+ buffer[index] = '\0';
+ }
+
+ if (length)
+ {
+ *length = index;
+ }
+}
+
+void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer)
+{
+ getSourceImpl(mSource, bufSize, length, buffer);
+}
+
+void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer)
+{
+ getSourceImpl(mHlsl, bufSize, length, buffer);
+}
+
+const sh::ActiveUniforms &Shader::getUniforms()
+{
+ return mActiveUniforms;
+}
+
+bool Shader::isCompiled()
+{
+ return mHlsl != NULL;
+}
+
+const char *Shader::getHLSL()
+{
+ return mHlsl;
+}
+
+void Shader::addRef()
+{
+ mRefCount++;
+}
+
+void Shader::release()
+{
+ mRefCount--;
+
+ if (mRefCount == 0 && mDeleteStatus)
+ {
+ mResourceManager->deleteShader(mHandle);
+ }
+}
+
+unsigned int Shader::getRefCount() const
+{
+ return mRefCount;
+}
+
+bool Shader::isFlaggedForDeletion() const
+{
+ return mDeleteStatus;
+}
+
+void Shader::flagForDeletion()
+{
+ mDeleteStatus = true;
+}
+
+// Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
+void Shader::initializeCompiler()
+{
+ if (!mFragmentCompiler)
+ {
+ int result = ShInitialize();
+
+ if (result)
+ {
+ ShShaderOutput hlslVersion = (mRenderer->getMajorShaderModel() >= 4) ? SH_HLSL11_OUTPUT : SH_HLSL9_OUTPUT;
+
+ ShBuiltInResources resources;
+ ShInitBuiltInResources(&resources);
+
+ resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
+ resources.MaxVertexUniformVectors = mRenderer->getMaxVertexUniformVectors();
+ resources.MaxVaryingVectors = mRenderer->getMaxVaryingVectors();
+ resources.MaxVertexTextureImageUnits = mRenderer->getMaxVertexTextureImageUnits();
+ resources.MaxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
+ resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+ resources.MaxFragmentUniformVectors = mRenderer->getMaxFragmentUniformVectors();
+ resources.MaxDrawBuffers = mRenderer->getMaxRenderTargets();
+ resources.OES_standard_derivatives = mRenderer->getDerivativeInstructionSupport();
+ resources.EXT_draw_buffers = mRenderer->getMaxRenderTargets() > 1;
+ // resources.OES_EGL_image_external = mRenderer->getShareHandleSupport() ? 1 : 0; // TODO: commented out until the extension is actually supported.
+ resources.FragmentPrecisionHigh = 1; // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp
+ resources.EXT_frag_depth = 1; // Shader Model 2+ always supports explicit depth output
+
+ mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, hlslVersion, &resources);
+ mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, hlslVersion, &resources);
+ }
+ }
+}
+
+void Shader::releaseCompiler()
+{
+ ShDestruct(mFragmentCompiler);
+ ShDestruct(mVertexCompiler);
+
+ mFragmentCompiler = NULL;
+ mVertexCompiler = NULL;
+
+ ShFinalize();
+}
+
+void Shader::parseVaryings()
+{
+ if (mHlsl)
+ {
+ const char *input = strstr(mHlsl, "// Varyings") + 12;
+
+ while(true)
+ {
+ char varyingType[256];
+ char varyingName[256];
+
+ int matches = sscanf(input, "static %255s %255s", varyingType, varyingName);
+
+ if (matches != 2)
+ {
+ break;
+ }
+
+ char *array = strstr(varyingName, "[");
+ int size = 1;
+
+ if (array)
+ {
+ size = atoi(array + 1);
+ *array = '\0';
+ }
+
+ mVaryings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
+
+ input = strstr(input, ";") + 2;
+ }
+
+ mUsesMultipleRenderTargets = strstr(mHlsl, "GL_USES_MRT") != NULL;
+ mUsesFragColor = strstr(mHlsl, "GL_USES_FRAG_COLOR") != NULL;
+ mUsesFragData = strstr(mHlsl, "GL_USES_FRAG_DATA") != NULL;
+ mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
+ mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
+ mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
+ mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
+ mUsesDepthRange = strstr(mHlsl, "GL_USES_DEPTH_RANGE") != NULL;
+ mUsesFragDepth = strstr(mHlsl, "GL_USES_FRAG_DEPTH") != NULL;
+ }
+}
+
+void Shader::resetVaryingsRegisterAssignment()
+{
+ for (VaryingList::iterator var = mVaryings.begin(); var != mVaryings.end(); var++)
+ {
+ var->reg = -1;
+ var->col = -1;
+ }
+}
+
+// initialize/clean up previous state
+void Shader::uncompile()
+{
+ // set by compileToHLSL
+ delete[] mHlsl;
+ mHlsl = NULL;
+ delete[] mInfoLog;
+ mInfoLog = NULL;
+
+ // set by parseVaryings
+ mVaryings.clear();
+
+ mUsesMultipleRenderTargets = false;
+ mUsesFragColor = false;
+ mUsesFragData = false;
+ mUsesFragCoord = false;
+ mUsesFrontFacing = false;
+ mUsesPointSize = false;
+ mUsesPointCoord = false;
+ mUsesDepthRange = false;
+ mUsesFragDepth = false;
+
+ mActiveUniforms.clear();
+}
+
+void Shader::compileToHLSL(void *compiler)
+{
+ // ensure we don't pass a NULL source to the compiler
+ const char *source = "\0";
+ if (mSource)
+ {
+ source = mSource;
+ }
+
+ // ensure the compiler is loaded
+ initializeCompiler();
+
+ int compileOptions = SH_OBJECT_CODE;
+ std::string sourcePath;
+ if (perfActive())
+ {
+ sourcePath = getTempPath();
+ writeFile(sourcePath.c_str(), source, strlen(source));
+ compileOptions |= SH_LINE_DIRECTIVES;
+ }
+
+ int result;
+ if (sourcePath.empty())
+ {
+ result = ShCompile(compiler, &source, 1, compileOptions);
+ }
+ else
+ {
+ const char* sourceStrings[2] =
+ {
+ sourcePath.c_str(),
+ source
+ };
+
+ result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH);
+ }
+
+ if (result)
+ {
+ size_t objCodeLen = 0;
+ ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
+ mHlsl = new char[objCodeLen];
+ ShGetObjectCode(compiler, mHlsl);
+
+ void *activeUniforms;
+ ShGetInfoPointer(compiler, SH_ACTIVE_UNIFORMS_ARRAY, &activeUniforms);
+ mActiveUniforms = *(sh::ActiveUniforms*)activeUniforms;
+ }
+ else
+ {
+ size_t infoLogLen = 0;
+ ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
+ mInfoLog = new char[infoLogLen];
+ ShGetInfoLog(compiler, mInfoLog);
+
+ TRACE("\n%s", mInfoLog);
+ }
+}
+
+GLenum Shader::parseType(const std::string &type)
+{
+ if (type == "float")
+ {
+ return GL_FLOAT;
+ }
+ else if (type == "float2")
+ {
+ return GL_FLOAT_VEC2;
+ }
+ else if (type == "float3")
+ {
+ return GL_FLOAT_VEC3;
+ }
+ else if (type == "float4")
+ {
+ return GL_FLOAT_VEC4;
+ }
+ else if (type == "float2x2")
+ {
+ return GL_FLOAT_MAT2;
+ }
+ else if (type == "float3x3")
+ {
+ return GL_FLOAT_MAT3;
+ }
+ else if (type == "float4x4")
+ {
+ return GL_FLOAT_MAT4;
+ }
+ else UNREACHABLE();
+
+ return GL_NONE;
+}
+
+// true if varying x has a higher priority in packing than y
+bool Shader::compareVarying(const Varying &x, const Varying &y)
+{
+ if(x.type == y.type)
+ {
+ return x.size > y.size;
+ }
+
+ switch (x.type)
+ {
+ case GL_FLOAT_MAT4: return true;
+ case GL_FLOAT_MAT2:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return true;
+ case GL_FLOAT_VEC4: return true;
+ case GL_FLOAT_MAT3: return true;
+ case GL_FLOAT_VEC3: return true;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT_VEC4:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return false;
+ case GL_FLOAT_VEC4: return true;
+ case GL_FLOAT_MAT3: return true;
+ case GL_FLOAT_VEC3: return true;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT_MAT3:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return false;
+ case GL_FLOAT_VEC4: return false;
+ case GL_FLOAT_MAT3: return true;
+ case GL_FLOAT_VEC3: return true;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT_VEC3:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return false;
+ case GL_FLOAT_VEC4: return false;
+ case GL_FLOAT_MAT3: return false;
+ case GL_FLOAT_VEC3: return true;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT_VEC2:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return false;
+ case GL_FLOAT_VEC4: return false;
+ case GL_FLOAT_MAT3: return false;
+ case GL_FLOAT_VEC3: return false;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT: return false;
+ default: UNREACHABLE();
+ }
+
+ return false;
+}
+
+VertexShader::VertexShader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle)
+ : Shader(manager, renderer, handle)
+{
+}
+
+VertexShader::~VertexShader()
+{
+}
+
+GLenum VertexShader::getType()
+{
+ return GL_VERTEX_SHADER;
+}
+
+void VertexShader::uncompile()
+{
+ Shader::uncompile();
+
+ // set by ParseAttributes
+ mAttributes.clear();
+}
+
+void VertexShader::compile()
+{
+ uncompile();
+
+ compileToHLSL(mVertexCompiler);
+ parseAttributes();
+ parseVaryings();
+}
+
+int VertexShader::getSemanticIndex(const std::string &attributeName)
+{
+ if (!attributeName.empty())
+ {
+ int semanticIndex = 0;
+ for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
+ {
+ if (attribute->name == attributeName)
+ {
+ return semanticIndex;
+ }
+
+ semanticIndex += VariableRowCount(attribute->type);
+ }
+ }
+
+ return -1;
+}
+
+void VertexShader::parseAttributes()
+{
+ const char *hlsl = getHLSL();
+ if (hlsl)
+ {
+ const char *input = strstr(hlsl, "// Attributes") + 14;
+
+ while(true)
+ {
+ char attributeType[256];
+ char attributeName[256];
+
+ int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
+
+ if (matches != 2)
+ {
+ break;
+ }
+
+ mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
+
+ input = strstr(input, ";") + 2;
+ }
+ }
+}
+
+FragmentShader::FragmentShader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle)
+ : Shader(manager, renderer, handle)
+{
+}
+
+FragmentShader::~FragmentShader()
+{
+}
+
+GLenum FragmentShader::getType()
+{
+ return GL_FRAGMENT_SHADER;
+}
+
+void FragmentShader::compile()
+{
+ uncompile();
+
+ compileToHLSL(mFragmentCompiler);
+ parseVaryings();
+ mVaryings.sort(compareVarying);
+}
+}
diff --git a/src/libGLESv2/Shader.h b/src/libGLESv2/Shader.h
new file mode 100644
index 00000000..2afe2976
--- /dev/null
+++ b/src/libGLESv2/Shader.h
@@ -0,0 +1,184 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Shader.h: Defines the abstract gl::Shader class and its concrete derived
+// classes VertexShader and FragmentShader. Implements GL shader objects and
+// related functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section
+// 3.8 page 84.
+
+#ifndef LIBGLESV2_SHADER_H_
+#define LIBGLESV2_SHADER_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <string>
+#include <list>
+#include <vector>
+
+#include "compiler/Uniform.h"
+#include "common/angleutils.h"
+
+namespace rx
+{
+class Renderer;
+}
+
+namespace gl
+{
+class ResourceManager;
+
+struct Varying
+{
+ Varying(GLenum type, const std::string &name, int size, bool array)
+ : type(type), name(name), size(size), array(array), reg(-1), col(-1)
+ {
+ }
+
+ GLenum type;
+ std::string name;
+ int size; // Number of 'type' elements
+ bool array;
+
+ int reg; // First varying register, assigned during link
+ int col; // First register element, assigned during link
+};
+
+typedef std::list<Varying> VaryingList;
+
+class Shader
+{
+ friend class ProgramBinary;
+
+ public:
+ Shader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle);
+
+ virtual ~Shader();
+
+ virtual GLenum getType() = 0;
+ GLuint getHandle() const;
+
+ void deleteSource();
+ void setSource(GLsizei count, const char **string, const GLint *length);
+ int getInfoLogLength() const;
+ void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
+ int getSourceLength() const;
+ void getSource(GLsizei bufSize, GLsizei *length, char *buffer);
+ int getTranslatedSourceLength() const;
+ void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer);
+ const sh::ActiveUniforms &getUniforms();
+
+ virtual void compile() = 0;
+ virtual void uncompile();
+ bool isCompiled();
+ const char *getHLSL();
+
+ void addRef();
+ void release();
+ unsigned int getRefCount() const;
+ bool isFlaggedForDeletion() const;
+ void flagForDeletion();
+
+ static void releaseCompiler();
+
+ protected:
+ void parseVaryings();
+ void resetVaryingsRegisterAssignment();
+
+ void compileToHLSL(void *compiler);
+
+ void getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer);
+
+ static GLenum parseType(const std::string &type);
+ static bool compareVarying(const Varying &x, const Varying &y);
+
+ const rx::Renderer *const mRenderer;
+
+ VaryingList mVaryings;
+
+ bool mUsesMultipleRenderTargets;
+ bool mUsesFragColor;
+ bool mUsesFragData;
+ bool mUsesFragCoord;
+ bool mUsesFrontFacing;
+ bool mUsesPointSize;
+ bool mUsesPointCoord;
+ bool mUsesDepthRange;
+ bool mUsesFragDepth;
+
+ static void *mFragmentCompiler;
+ static void *mVertexCompiler;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Shader);
+
+ void initializeCompiler();
+
+ const GLuint mHandle;
+ 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
+
+ char *mSource;
+ char *mHlsl;
+ char *mInfoLog;
+ sh::ActiveUniforms mActiveUniforms;
+
+ ResourceManager *mResourceManager;
+};
+
+struct Attribute
+{
+ Attribute() : type(GL_NONE), name("")
+ {
+ }
+
+ Attribute(GLenum type, const std::string &name) : type(type), name(name)
+ {
+ }
+
+ GLenum type;
+ std::string name;
+};
+
+typedef std::vector<Attribute> AttributeArray;
+
+class VertexShader : public Shader
+{
+ friend class ProgramBinary;
+
+ public:
+ VertexShader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle);
+
+ ~VertexShader();
+
+ virtual GLenum getType();
+ virtual void compile();
+ virtual void uncompile();
+ int getSemanticIndex(const std::string &attributeName);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexShader);
+
+ void parseAttributes();
+
+ AttributeArray mAttributes;
+};
+
+class FragmentShader : public Shader
+{
+ public:
+ FragmentShader(ResourceManager *manager,const rx::Renderer *renderer, GLuint handle);
+
+ ~FragmentShader();
+
+ virtual GLenum getType();
+ virtual void compile();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FragmentShader);
+};
+}
+
+#endif // LIBGLESV2_SHADER_H_
diff --git a/src/libGLESv2/Texture.cpp b/src/libGLESv2/Texture.cpp
new file mode 100644
index 00000000..ae830378
--- /dev/null
+++ b/src/libGLESv2/Texture.cpp
@@ -0,0 +1,1495 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Texture.cpp: Implements the gl::Texture class and its derived classes
+// Texture2D and TextureCubeMap. Implements GL texture objects and related
+// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
+
+#include "libGLESv2/Texture.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/renderer/Blit.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/renderer/Image.h"
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/renderer/TextureStorage.h"
+#include "libEGL/Surface.h"
+
+namespace gl
+{
+
+Texture::Texture(rx::Renderer *renderer, GLuint id) : RefCountObject(id)
+{
+ mRenderer = renderer;
+
+ mSamplerState.minFilter = GL_NEAREST_MIPMAP_LINEAR;
+ mSamplerState.magFilter = GL_LINEAR;
+ mSamplerState.wrapS = GL_REPEAT;
+ mSamplerState.wrapT = GL_REPEAT;
+ mSamplerState.maxAnisotropy = 1.0f;
+ mSamplerState.lodOffset = 0;
+ mUsage = GL_NONE;
+
+ mDirtyImages = true;
+
+ mImmutable = false;
+}
+
+Texture::~Texture()
+{
+}
+
+// Returns true on successful filter state update (valid enum parameter)
+bool Texture::setMinFilter(GLenum filter)
+{
+ switch (filter)
+ {
+ 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:
+ mSamplerState.minFilter = filter;
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful filter state update (valid enum parameter)
+bool Texture::setMagFilter(GLenum filter)
+{
+ switch (filter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ mSamplerState.magFilter = filter;
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful wrap state update (valid enum parameter)
+bool Texture::setWrapS(GLenum wrap)
+{
+ switch (wrap)
+ {
+ case GL_REPEAT:
+ case GL_CLAMP_TO_EDGE:
+ case GL_MIRRORED_REPEAT:
+ mSamplerState.wrapS = wrap;
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful wrap state update (valid enum parameter)
+bool Texture::setWrapT(GLenum wrap)
+{
+ switch (wrap)
+ {
+ case GL_REPEAT:
+ case GL_CLAMP_TO_EDGE:
+ case GL_MIRRORED_REPEAT:
+ mSamplerState.wrapT = wrap;
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful max anisotropy update (valid anisotropy value)
+bool Texture::setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy)
+{
+ textureMaxAnisotropy = std::min(textureMaxAnisotropy, contextMaxAnisotropy);
+ if (textureMaxAnisotropy < 1.0f)
+ {
+ return false;
+ }
+
+ mSamplerState.maxAnisotropy = textureMaxAnisotropy;
+
+ return true;
+}
+
+// Returns true on successful usage state update (valid enum parameter)
+bool Texture::setUsage(GLenum usage)
+{
+ switch (usage)
+ {
+ case GL_NONE:
+ case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
+ mUsage = usage;
+ return true;
+ default:
+ return false;
+ }
+}
+
+GLenum Texture::getMinFilter() const
+{
+ return mSamplerState.minFilter;
+}
+
+GLenum Texture::getMagFilter() const
+{
+ return mSamplerState.magFilter;
+}
+
+GLenum Texture::getWrapS() const
+{
+ return mSamplerState.wrapS;
+}
+
+GLenum Texture::getWrapT() const
+{
+ return mSamplerState.wrapT;
+}
+
+float Texture::getMaxAnisotropy() const
+{
+ return mSamplerState.maxAnisotropy;
+}
+
+int Texture::getLodOffset()
+{
+ rx::TextureStorageInterface *texture = getStorage(false);
+ return texture ? texture->getLodOffset() : 0;
+}
+
+void Texture::getSamplerState(SamplerState *sampler)
+{
+ *sampler = mSamplerState;
+ sampler->lodOffset = getLodOffset();
+}
+
+GLenum Texture::getUsage() const
+{
+ return mUsage;
+}
+
+bool Texture::isMipmapFiltered() const
+{
+ switch (mSamplerState.minFilter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ return false;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ return true;
+ default: UNREACHABLE();
+ return false;
+ }
+}
+
+void Texture::setImage(GLint unpackAlignment, const void *pixels, rx::Image *image)
+{
+ if (pixels != NULL)
+ {
+ image->loadData(0, 0, image->getWidth(), image->getHeight(), unpackAlignment, pixels);
+ mDirtyImages = true;
+ }
+}
+
+void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
+{
+ if (pixels != NULL)
+ {
+ image->loadCompressedData(0, 0, image->getWidth(), image->getHeight(), pixels);
+ mDirtyImages = true;
+ }
+}
+
+bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image)
+{
+ if (pixels != NULL)
+ {
+ image->loadData(xoffset, yoffset, width, height, unpackAlignment, pixels);
+ mDirtyImages = true;
+ }
+
+ return true;
+}
+
+bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
+{
+ if (pixels != NULL)
+ {
+ image->loadCompressedData(xoffset, yoffset, width, height, pixels);
+ mDirtyImages = true;
+ }
+
+ return true;
+}
+
+rx::TextureStorageInterface *Texture::getNativeTexture()
+{
+ // ensure the underlying texture is created
+
+ rx::TextureStorageInterface *storage = getStorage(false);
+ if (storage)
+ {
+ updateTexture();
+ }
+
+ return storage;
+}
+
+bool Texture::hasDirtyImages() const
+{
+ return mDirtyImages;
+}
+
+void Texture::resetDirty()
+{
+ mDirtyImages = false;
+}
+
+unsigned int Texture::getTextureSerial()
+{
+ rx::TextureStorageInterface *texture = getStorage(false);
+ return texture ? texture->getTextureSerial() : 0;
+}
+
+unsigned int Texture::getRenderTargetSerial(GLenum target)
+{
+ rx::TextureStorageInterface *texture = getStorage(true);
+ return texture ? texture->getRenderTargetSerial(target) : 0;
+}
+
+bool Texture::isImmutable() const
+{
+ return mImmutable;
+}
+
+GLint Texture::creationLevels(GLsizei width, GLsizei height) const
+{
+ if ((isPow2(width) && isPow2(height)) || mRenderer->getNonPower2TextureSupport())
+ {
+ return 0; // Maximum number of levels
+ }
+ else
+ {
+ // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
+ return 1;
+ }
+}
+
+GLint Texture::creationLevels(GLsizei size) const
+{
+ return creationLevels(size, size);
+}
+
+Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
+{
+ mTexStorage = NULL;
+ mSurface = NULL;
+ mColorbufferProxy = NULL;
+ mProxyRefs = 0;
+
+ for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
+ {
+ mImageArray[i] = renderer->createImage();
+ }
+}
+
+Texture2D::~Texture2D()
+{
+ mColorbufferProxy = NULL;
+
+ delete mTexStorage;
+ mTexStorage = NULL;
+
+ if (mSurface)
+ {
+ mSurface->setBoundTexture(NULL);
+ mSurface = NULL;
+ }
+
+ for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
+ {
+ delete mImageArray[i];
+ }
+}
+
+// We need to maintain a count of references to renderbuffers acting as
+// proxies for this texture, so that we do not attempt to use a pointer
+// to a renderbuffer proxy which has been deleted.
+void Texture2D::addProxyRef(const Renderbuffer *proxy)
+{
+ mProxyRefs++;
+}
+
+void Texture2D::releaseProxy(const Renderbuffer *proxy)
+{
+ if (mProxyRefs > 0)
+ mProxyRefs--;
+
+ if (mProxyRefs == 0)
+ mColorbufferProxy = NULL;
+}
+
+GLenum Texture2D::getTarget() const
+{
+ return GL_TEXTURE_2D;
+}
+
+GLsizei Texture2D::getWidth(GLint level) const
+{
+ if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ return mImageArray[level]->getWidth();
+ else
+ return 0;
+}
+
+GLsizei Texture2D::getHeight(GLint level) const
+{
+ if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ return mImageArray[level]->getHeight();
+ else
+ return 0;
+}
+
+GLenum Texture2D::getInternalFormat(GLint level) const
+{
+ if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ return mImageArray[level]->getInternalFormat();
+ else
+ return GL_NONE;
+}
+
+GLenum Texture2D::getActualFormat(GLint level) const
+{
+ if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ return mImageArray[level]->getActualFormat();
+ else
+ return D3DFMT_UNKNOWN;
+}
+
+void Texture2D::redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height)
+{
+ releaseTexImage();
+
+ // If there currently is a corresponding storage texture image, it has these parameters
+ const int storageWidth = std::max(1, mImageArray[0]->getWidth() >> level);
+ const int storageHeight = std::max(1, mImageArray[0]->getHeight() >> level);
+ const int storageFormat = mImageArray[0]->getInternalFormat();
+
+ mImageArray[level]->redefine(mRenderer, internalformat, width, height, false);
+
+ if (mTexStorage)
+ {
+ const int storageLevels = mTexStorage->levelCount();
+
+ if ((level >= storageLevels && storageLevels != 0) ||
+ width != storageWidth ||
+ height != storageHeight ||
+ internalformat != storageFormat) // Discard mismatched storage
+ {
+ for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ mImageArray[i]->markDirty();
+ }
+
+ delete mTexStorage;
+ mTexStorage = NULL;
+ mDirtyImages = true;
+ }
+ }
+}
+
+void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ GLint internalformat = ConvertSizedInternalFormat(format, type);
+ redefineImage(level, internalformat, width, height);
+
+ Texture::setImage(unpackAlignment, pixels, mImageArray[level]);
+}
+
+void Texture2D::bindTexImage(egl::Surface *surface)
+{
+ releaseTexImage();
+
+ GLint internalformat = surface->getFormat();
+
+ mImageArray[0]->redefine(mRenderer, internalformat, surface->getWidth(), surface->getHeight(), true);
+
+ delete mTexStorage;
+ mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
+
+ mDirtyImages = true;
+ mSurface = surface;
+ mSurface->setBoundTexture(this);
+}
+
+void Texture2D::releaseTexImage()
+{
+ if (mSurface)
+ {
+ mSurface->setBoundTexture(NULL);
+ mSurface = NULL;
+
+ if (mTexStorage)
+ {
+ delete mTexStorage;
+ mTexStorage = NULL;
+ }
+
+ for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ mImageArray[i]->redefine(mRenderer, GL_NONE, 0, 0, true);
+ }
+ }
+}
+
+void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+{
+ // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
+ redefineImage(level, format, width, height);
+
+ Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
+}
+
+void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ if (level < levelCount())
+ {
+ rx::Image *image = mImageArray[level];
+ if (image->updateSurface(mTexStorage, level, xoffset, yoffset, width, height))
+ {
+ image->markClean();
+ }
+ }
+}
+
+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[level]))
+ {
+ commitRect(level, xoffset, yoffset, width, height);
+ }
+}
+
+void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
+{
+ if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[level]))
+ {
+ commitRect(level, xoffset, yoffset, width, height);
+ }
+}
+
+void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ GLint internalformat = ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
+ redefineImage(level, internalformat, width, height);
+
+ if (!mImageArray[level]->isRenderableFormat())
+ {
+ mImageArray[level]->copy(0, 0, x, y, width, height, source);
+ mDirtyImages = true;
+ }
+ else
+ {
+ if (!mTexStorage || !mTexStorage->isRenderTarget())
+ {
+ convertToRenderTarget();
+ }
+
+ mImageArray[level]->markClean();
+
+ if (width != 0 && height != 0 && level < levelCount())
+ {
+ gl::Rectangle sourceRect;
+ sourceRect.x = x;
+ sourceRect.width = width;
+ sourceRect.y = y;
+ sourceRect.height = height;
+
+ mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
+ }
+ }
+}
+
+void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
+ {
+ mImageArray[level]->copy(xoffset, yoffset, x, y, width, height, source);
+ mDirtyImages = true;
+ }
+ else
+ {
+ if (!mTexStorage || !mTexStorage->isRenderTarget())
+ {
+ convertToRenderTarget();
+ }
+
+ updateTexture();
+
+ if (level < levelCount())
+ {
+ gl::Rectangle sourceRect;
+ sourceRect.x = x;
+ sourceRect.width = width;
+ sourceRect.y = y;
+ sourceRect.height = height;
+
+ mRenderer->copyImage(source, sourceRect,
+ gl::ExtractFormat(mImageArray[0]->getInternalFormat()),
+ xoffset, yoffset, mTexStorage, level);
+ }
+ }
+}
+
+void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ delete mTexStorage;
+ mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
+ mImmutable = true;
+
+ for (int level = 0; level < levels; level++)
+ {
+ mImageArray[level]->redefine(mRenderer, internalformat, width, height, true);
+ width = std::max(1, width >> 1);
+ height = std::max(1, height >> 1);
+ }
+
+ for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
+ {
+ mImageArray[level]->redefine(mRenderer, GL_NONE, 0, 0, true);
+ }
+
+ if (mTexStorage->isManaged())
+ {
+ int levels = levelCount();
+
+ for (int level = 0; level < levels; level++)
+ {
+ mImageArray[level]->setManagedSurface(mTexStorage, level);
+ }
+ }
+}
+
+// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
+bool Texture2D::isSamplerComplete() const
+{
+ GLsizei width = mImageArray[0]->getWidth();
+ GLsizei height = mImageArray[0]->getHeight();
+
+ if (width <= 0 || height <= 0)
+ {
+ return false;
+ }
+
+ bool mipmapping = isMipmapFiltered();
+ bool filtering, renderable;
+
+ if ((IsFloat32Format(getInternalFormat(0)) && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
+ (IsFloat16Format(getInternalFormat(0)) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
+ {
+ if (mSamplerState.magFilter != GL_NEAREST ||
+ (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
+ {
+ return false;
+ }
+ }
+
+ bool npotSupport = mRenderer->getNonPower2TextureSupport();
+
+ if (!npotSupport)
+ {
+ if ((mSamplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
+ (mSamplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
+ {
+ return false;
+ }
+ }
+
+ if (mipmapping)
+ {
+ if (!npotSupport)
+ {
+ if (!isPow2(width) || !isPow2(height))
+ {
+ return false;
+ }
+ }
+
+ if (!isMipmapComplete())
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+bool Texture2D::isMipmapComplete() const
+{
+ if (isImmutable())
+ {
+ return true;
+ }
+
+ GLsizei width = mImageArray[0]->getWidth();
+ GLsizei height = mImageArray[0]->getHeight();
+
+ if (width <= 0 || height <= 0)
+ {
+ return false;
+ }
+
+ int q = log2(std::max(width, height));
+
+ for (int level = 1; level <= q; level++)
+ {
+ if (mImageArray[level]->getInternalFormat() != mImageArray[0]->getInternalFormat())
+ {
+ return false;
+ }
+
+ if (mImageArray[level]->getWidth() != std::max(1, width >> level))
+ {
+ return false;
+ }
+
+ if (mImageArray[level]->getHeight() != std::max(1, height >> level))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool Texture2D::isCompressed(GLint level) const
+{
+ return IsCompressed(getInternalFormat(level));
+}
+
+bool Texture2D::isDepth(GLint level) const
+{
+ return IsDepthTexture(getInternalFormat(level));
+}
+
+// Constructs a native texture resource from the texture images
+void Texture2D::createTexture()
+{
+ GLsizei width = mImageArray[0]->getWidth();
+ GLsizei height = mImageArray[0]->getHeight();
+
+ if (!(width > 0 && height > 0))
+ return; // do not attempt to create native textures for nonexistant data
+
+ GLint levels = creationLevels(width, height);
+ GLenum internalformat = mImageArray[0]->getInternalFormat();
+
+ delete mTexStorage;
+ mTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, mUsage, false, width, height);
+
+ if (mTexStorage->isManaged())
+ {
+ int levels = levelCount();
+
+ for (int level = 0; level < levels; level++)
+ {
+ mImageArray[level]->setManagedSurface(mTexStorage, level);
+ }
+ }
+
+ mDirtyImages = true;
+}
+
+void Texture2D::updateTexture()
+{
+ bool mipmapping = (isMipmapFiltered() && isMipmapComplete());
+
+ int levels = (mipmapping ? levelCount() : 1);
+
+ for (int level = 0; level < levels; level++)
+ {
+ rx::Image *image = mImageArray[level];
+
+ if (image->isDirty())
+ {
+ commitRect(level, 0, 0, mImageArray[level]->getWidth(), mImageArray[level]->getHeight());
+ }
+ }
+}
+
+void Texture2D::convertToRenderTarget()
+{
+ rx::TextureStorageInterface2D *newTexStorage = NULL;
+
+ if (mImageArray[0]->getWidth() != 0 && mImageArray[0]->getHeight() != 0)
+ {
+ GLsizei width = mImageArray[0]->getWidth();
+ GLsizei height = mImageArray[0]->getHeight();
+ GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(width, height);
+ GLenum internalformat = mImageArray[0]->getInternalFormat();
+
+ newTexStorage = new rx::TextureStorageInterface2D(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, width, height);
+
+ if (mTexStorage != NULL)
+ {
+ if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
+ {
+ delete newTexStorage;
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+ }
+
+ delete mTexStorage;
+ mTexStorage = newTexStorage;
+
+ mDirtyImages = true;
+}
+
+void Texture2D::generateMipmaps()
+{
+ if (!mRenderer->getNonPower2TextureSupport())
+ {
+ if (!isPow2(mImageArray[0]->getWidth()) || !isPow2(mImageArray[0]->getHeight()))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+
+ // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
+ unsigned int q = log2(std::max(mImageArray[0]->getWidth(), mImageArray[0]->getHeight()));
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ redefineImage(i, mImageArray[0]->getInternalFormat(),
+ std::max(mImageArray[0]->getWidth() >> i, 1),
+ std::max(mImageArray[0]->getHeight() >> i, 1));
+ }
+
+ if (mTexStorage && mTexStorage->isRenderTarget())
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ mTexStorage->generateMipmap(i);
+
+ mImageArray[i]->markClean();
+ }
+ }
+ else
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ mRenderer->generateMipmap(mImageArray[i], mImageArray[i - 1]);
+ }
+ }
+}
+
+Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
+{
+ if (target != GL_TEXTURE_2D)
+ {
+ return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
+ }
+
+ if (mColorbufferProxy == NULL)
+ {
+ mColorbufferProxy = new Renderbuffer(mRenderer, id(), new RenderbufferTexture2D(this, target));
+ }
+
+ return mColorbufferProxy;
+}
+
+rx::RenderTarget *Texture2D::getRenderTarget(GLenum target)
+{
+ ASSERT(target == GL_TEXTURE_2D);
+
+ // ensure the underlying texture is created
+ if (getStorage(true) == NULL)
+ {
+ return NULL;
+ }
+
+ updateTexture();
+
+ // ensure this is NOT a depth texture
+ if (isDepth(0))
+ {
+ return NULL;
+ }
+
+ return mTexStorage->getRenderTarget();
+}
+
+rx::RenderTarget *Texture2D::getDepthStencil(GLenum target)
+{
+ ASSERT(target == GL_TEXTURE_2D);
+
+ // ensure the underlying texture is created
+ if (getStorage(true) == NULL)
+ {
+ return NULL;
+ }
+
+ updateTexture();
+
+ // ensure this is actually a depth texture
+ if (!isDepth(0))
+ {
+ return NULL;
+ }
+ return mTexStorage->getRenderTarget();
+}
+
+int Texture2D::levelCount()
+{
+ return mTexStorage ? mTexStorage->levelCount() : 0;
+}
+
+rx::TextureStorageInterface *Texture2D::getStorage(bool renderTarget)
+{
+ if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
+ {
+ if (renderTarget)
+ {
+ convertToRenderTarget();
+ }
+ else
+ {
+ createTexture();
+ }
+ }
+
+ return mTexStorage;
+}
+
+TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id)
+{
+ mTexStorage = NULL;
+ for (int i = 0; i < 6; i++)
+ {
+ mFaceProxies[i] = NULL;
+ mFaceProxyRefs[i] = 0;
+
+ for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
+ {
+ mImageArray[i][j] = renderer->createImage();
+ }
+ }
+}
+
+TextureCubeMap::~TextureCubeMap()
+{
+ for (int i = 0; i < 6; i++)
+ {
+ mFaceProxies[i] = NULL;
+
+ for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
+ {
+ delete mImageArray[i][j];
+ }
+ }
+
+ delete mTexStorage;
+ mTexStorage = NULL;
+}
+
+// We need to maintain a count of references to renderbuffers acting as
+// proxies for this texture, so that the texture is not deleted while
+// proxy references still exist. If the reference count drops to zero,
+// we set our proxy pointer NULL, so that a new attempt at referencing
+// will cause recreation.
+void TextureCubeMap::addProxyRef(const Renderbuffer *proxy)
+{
+ for (int i = 0; i < 6; i++)
+ {
+ if (mFaceProxies[i] == proxy)
+ mFaceProxyRefs[i]++;
+ }
+}
+
+void TextureCubeMap::releaseProxy(const Renderbuffer *proxy)
+{
+ for (int i = 0; i < 6; i++)
+ {
+ if (mFaceProxies[i] == proxy)
+ {
+ if (mFaceProxyRefs[i] > 0)
+ mFaceProxyRefs[i]--;
+
+ if (mFaceProxyRefs[i] == 0)
+ mFaceProxies[i] = NULL;
+ }
+ }
+}
+
+GLenum TextureCubeMap::getTarget() const
+{
+ return GL_TEXTURE_CUBE_MAP;
+}
+
+GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
+{
+ if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ return mImageArray[faceIndex(target)][level]->getWidth();
+ else
+ return 0;
+}
+
+GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
+{
+ if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ return mImageArray[faceIndex(target)][level]->getHeight();
+ else
+ return 0;
+}
+
+GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
+{
+ if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ return mImageArray[faceIndex(target)][level]->getInternalFormat();
+ else
+ return GL_NONE;
+}
+
+GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
+{
+ if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
+ return mImageArray[faceIndex(target)][level]->getActualFormat();
+ else
+ return D3DFMT_UNKNOWN;
+}
+
+void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(0, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(1, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(2, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(3, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(4, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(5, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+{
+ // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
+ redefineImage(faceIndex(face), level, format, width, height);
+
+ Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex(face)][level]);
+}
+
+void TextureCubeMap::commitRect(int face, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ if (level < levelCount())
+ {
+ rx::Image *image = mImageArray[face][level];
+ if (image->updateSurface(mTexStorage, face, level, xoffset, yoffset, width, height))
+ image->markClean();
+ }
+}
+
+void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, mImageArray[faceIndex(target)][level]))
+ {
+ commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
+ }
+}
+
+void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
+{
+ if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, mImageArray[faceIndex(target)][level]))
+ {
+ commitRect(faceIndex(target), level, xoffset, yoffset, width, height);
+ }
+}
+
+// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
+bool TextureCubeMap::isSamplerComplete() const
+{
+ int size = mImageArray[0][0]->getWidth();
+
+ bool mipmapping = isMipmapFiltered();
+ bool filtering, renderable;
+
+ if ((gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)) == GL_FLOAT && !mRenderer->getFloat32TextureSupport(&filtering, &renderable)) ||
+ (gl::ExtractType(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0) == GL_HALF_FLOAT_OES) && !mRenderer->getFloat16TextureSupport(&filtering, &renderable)))
+ {
+ if (mSamplerState.magFilter != GL_NEAREST ||
+ (mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
+ {
+ return false;
+ }
+ }
+
+ if (!isPow2(size) && !mRenderer->getNonPower2TextureSupport())
+ {
+ if (mSamplerState.wrapS != GL_CLAMP_TO_EDGE || mSamplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
+ {
+ return false;
+ }
+ }
+
+ if (!mipmapping)
+ {
+ if (!isCubeComplete())
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+bool TextureCubeMap::isCubeComplete() const
+{
+ if (mImageArray[0][0]->getWidth() <= 0 || mImageArray[0][0]->getHeight() != mImageArray[0][0]->getWidth())
+ {
+ return false;
+ }
+
+ for (unsigned int face = 1; face < 6; face++)
+ {
+ if (mImageArray[face][0]->getWidth() != mImageArray[0][0]->getWidth() ||
+ mImageArray[face][0]->getWidth() != mImageArray[0][0]->getHeight() ||
+ mImageArray[face][0]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool TextureCubeMap::isMipmapCubeComplete() const
+{
+ if (isImmutable())
+ {
+ return true;
+ }
+
+ if (!isCubeComplete())
+ {
+ return false;
+ }
+
+ GLsizei size = mImageArray[0][0]->getWidth();
+
+ int q = log2(size);
+
+ for (int face = 0; face < 6; face++)
+ {
+ for (int level = 1; level <= q; level++)
+ {
+ if (mImageArray[face][level]->getInternalFormat() != mImageArray[0][0]->getInternalFormat())
+ {
+ return false;
+ }
+
+ if (mImageArray[face][level]->getWidth() != std::max(1, size >> level))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
+{
+ return IsCompressed(getInternalFormat(target, level));
+}
+
+// Constructs a native texture resource from the texture images, or returns an existing one
+void TextureCubeMap::createTexture()
+{
+ GLsizei size = mImageArray[0][0]->getWidth();
+
+ if (!(size > 0))
+ return; // do not attempt to create native textures for nonexistant data
+
+ GLint levels = creationLevels(size);
+ GLenum internalformat = mImageArray[0][0]->getInternalFormat();
+
+ delete mTexStorage;
+ mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
+
+ if (mTexStorage->isManaged())
+ {
+ int levels = levelCount();
+
+ for (int face = 0; face < 6; face++)
+ {
+ for (int level = 0; level < levels; level++)
+ {
+ mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
+ }
+ }
+ }
+
+ mDirtyImages = true;
+}
+
+void TextureCubeMap::updateTexture()
+{
+ bool mipmapping = isMipmapFiltered() && isMipmapCubeComplete();
+
+ for (int face = 0; face < 6; face++)
+ {
+ int levels = (mipmapping ? levelCount() : 1);
+
+ for (int level = 0; level < levels; level++)
+ {
+ rx::Image *image = mImageArray[face][level];
+
+ if (image->isDirty())
+ {
+ commitRect(face, level, 0, 0, image->getWidth(), image->getHeight());
+ }
+ }
+ }
+}
+
+void TextureCubeMap::convertToRenderTarget()
+{
+ rx::TextureStorageInterfaceCube *newTexStorage = NULL;
+
+ if (mImageArray[0][0]->getWidth() != 0)
+ {
+ GLsizei size = mImageArray[0][0]->getWidth();
+ GLint levels = mTexStorage != NULL ? mTexStorage->levelCount() : creationLevels(size);
+ GLenum internalformat = mImageArray[0][0]->getInternalFormat();
+
+ newTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, GL_FRAMEBUFFER_ATTACHMENT_ANGLE, true, size);
+
+ if (mTexStorage != NULL)
+ {
+ if (!mRenderer->copyToRenderTarget(newTexStorage, mTexStorage))
+ {
+ delete newTexStorage;
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+ }
+
+ delete mTexStorage;
+ mTexStorage = newTexStorage;
+
+ mDirtyImages = true;
+}
+
+void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ GLint internalformat = ConvertSizedInternalFormat(format, type);
+ redefineImage(faceIndex, level, internalformat, width, height);
+
+ Texture::setImage(unpackAlignment, pixels, mImageArray[faceIndex][level]);
+}
+
+unsigned int TextureCubeMap::faceIndex(GLenum face)
+{
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
+
+ return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+}
+
+void TextureCubeMap::redefineImage(int face, GLint level, GLint internalformat, GLsizei width, GLsizei height)
+{
+ // If there currently is a corresponding storage texture image, it has these parameters
+ const int storageWidth = std::max(1, mImageArray[0][0]->getWidth() >> level);
+ const int storageHeight = std::max(1, mImageArray[0][0]->getHeight() >> level);
+ const int storageFormat = mImageArray[0][0]->getInternalFormat();
+
+ mImageArray[face][level]->redefine(mRenderer, internalformat, width, height, false);
+
+ if (mTexStorage)
+ {
+ const int storageLevels = mTexStorage->levelCount();
+
+ if ((level >= storageLevels && storageLevels != 0) ||
+ width != storageWidth ||
+ height != storageHeight ||
+ internalformat != storageFormat) // Discard mismatched storage
+ {
+ for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ for (int f = 0; f < 6; f++)
+ {
+ mImageArray[f][i]->markDirty();
+ }
+ }
+
+ delete mTexStorage;
+ mTexStorage = NULL;
+
+ mDirtyImages = true;
+ }
+ }
+}
+
+void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ unsigned int faceindex = faceIndex(target);
+ GLint internalformat = gl::ConvertSizedInternalFormat(format, GL_UNSIGNED_BYTE);
+ redefineImage(faceindex, level, internalformat, width, height);
+
+ if (!mImageArray[faceindex][level]->isRenderableFormat())
+ {
+ mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
+ mDirtyImages = true;
+ }
+ else
+ {
+ if (!mTexStorage || !mTexStorage->isRenderTarget())
+ {
+ convertToRenderTarget();
+ }
+
+ mImageArray[faceindex][level]->markClean();
+
+ ASSERT(width == height);
+
+ if (width > 0 && level < levelCount())
+ {
+ gl::Rectangle sourceRect;
+ sourceRect.x = x;
+ sourceRect.width = width;
+ sourceRect.y = y;
+ sourceRect.height = height;
+
+ mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
+ }
+ }
+}
+
+void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ GLsizei size = mImageArray[faceIndex(target)][level]->getWidth();
+
+ if (xoffset + width > size || yoffset + height > size)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ unsigned int faceindex = faceIndex(target);
+
+ if (!mImageArray[faceindex][level]->isRenderableFormat() || (!mTexStorage && !isSamplerComplete()))
+ {
+ mImageArray[faceindex][level]->copy(0, 0, x, y, width, height, source);
+ mDirtyImages = true;
+ }
+ else
+ {
+ if (!mTexStorage || !mTexStorage->isRenderTarget())
+ {
+ convertToRenderTarget();
+ }
+
+ updateTexture();
+
+ if (level < levelCount())
+ {
+ gl::Rectangle sourceRect;
+ sourceRect.x = x;
+ sourceRect.width = width;
+ sourceRect.y = y;
+ sourceRect.height = height;
+
+ mRenderer->copyImage(source, sourceRect, gl::ExtractFormat(mImageArray[0][0]->getInternalFormat()),
+ xoffset, yoffset, mTexStorage, target, level);
+ }
+ }
+}
+
+void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
+{
+ delete mTexStorage;
+ mTexStorage = new rx::TextureStorageInterfaceCube(mRenderer, levels, internalformat, mUsage, false, size);
+ mImmutable = true;
+
+ for (int level = 0; level < levels; level++)
+ {
+ for (int face = 0; face < 6; face++)
+ {
+ mImageArray[face][level]->redefine(mRenderer, internalformat, size, size, true);
+ size = std::max(1, size >> 1);
+ }
+ }
+
+ for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
+ {
+ for (int face = 0; face < 6; face++)
+ {
+ mImageArray[face][level]->redefine(mRenderer, GL_NONE, 0, 0, true);
+ }
+ }
+
+ if (mTexStorage->isManaged())
+ {
+ int levels = levelCount();
+
+ for (int face = 0; face < 6; face++)
+ {
+ for (int level = 0; level < levels; level++)
+ {
+ mImageArray[face][level]->setManagedSurface(mTexStorage, face, level);
+ }
+ }
+ }
+}
+
+void TextureCubeMap::generateMipmaps()
+{
+ if (!isCubeComplete())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!mRenderer->getNonPower2TextureSupport())
+ {
+ if (!isPow2(mImageArray[0][0]->getWidth()))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+
+ // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
+ unsigned int q = log2(mImageArray[0][0]->getWidth());
+ for (unsigned int f = 0; f < 6; f++)
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ redefineImage(f, i, mImageArray[f][0]->getInternalFormat(),
+ std::max(mImageArray[f][0]->getWidth() >> i, 1),
+ std::max(mImageArray[f][0]->getWidth() >> i, 1));
+ }
+ }
+
+ if (mTexStorage && mTexStorage->isRenderTarget())
+ {
+ for (unsigned int f = 0; f < 6; f++)
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ mTexStorage->generateMipmap(f, i);
+
+ mImageArray[f][i]->markClean();
+ }
+ }
+ }
+ else
+ {
+ for (unsigned int f = 0; f < 6; f++)
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ mRenderer->generateMipmap(mImageArray[f][i], mImageArray[f][i - 1]);
+ }
+ }
+ }
+}
+
+Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
+{
+ if (!IsCubemapTextureTarget(target))
+ {
+ return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
+ }
+
+ unsigned int face = faceIndex(target);
+
+ if (mFaceProxies[face] == NULL)
+ {
+ mFaceProxies[face] = new Renderbuffer(mRenderer, id(), new RenderbufferTextureCubeMap(this, target));
+ }
+
+ return mFaceProxies[face];
+}
+
+rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target)
+{
+ ASSERT(IsCubemapTextureTarget(target));
+
+ // ensure the underlying texture is created
+ if (getStorage(true) == NULL)
+ {
+ return NULL;
+ }
+
+ updateTexture();
+
+ return mTexStorage->getRenderTarget(target);
+}
+
+int TextureCubeMap::levelCount()
+{
+ return mTexStorage ? mTexStorage->levelCount() - getLodOffset() : 0;
+}
+
+rx::TextureStorageInterface *TextureCubeMap::getStorage(bool renderTarget)
+{
+ if (!mTexStorage || (renderTarget && !mTexStorage->isRenderTarget()))
+ {
+ if (renderTarget)
+ {
+ convertToRenderTarget();
+ }
+ else
+ {
+ createTexture();
+ }
+ }
+
+ return mTexStorage;
+}
+
+}
diff --git a/src/libGLESv2/Texture.h b/src/libGLESv2/Texture.h
new file mode 100644
index 00000000..4f5fab28
--- /dev/null
+++ b/src/libGLESv2/Texture.h
@@ -0,0 +1,275 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Texture.h: Defines the abstract gl::Texture class and its concrete derived
+// classes Texture2D and TextureCubeMap. Implements GL texture objects and
+// related functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
+
+#ifndef LIBGLESV2_TEXTURE_H_
+#define LIBGLESV2_TEXTURE_H_
+
+#include <vector>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "common/debug.h"
+#include "common/RefCountObject.h"
+#include "libGLESv2/angletypes.h"
+
+namespace egl
+{
+class Surface;
+}
+
+namespace rx
+{
+class Renderer;
+class TextureStorageInterface;
+class TextureStorageInterface2D;
+class TextureStorageInterfaceCube;
+class RenderTarget;
+class Image;
+}
+
+namespace gl
+{
+class Framebuffer;
+class Renderbuffer;
+
+enum
+{
+ // 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_TEXTURE_SIZE = 16384,
+ IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384,
+
+ IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE
+};
+
+class Texture : public RefCountObject
+{
+ public:
+ Texture(rx::Renderer *renderer, GLuint id);
+
+ virtual ~Texture();
+
+ virtual void addProxyRef(const Renderbuffer *proxy) = 0;
+ virtual void releaseProxy(const Renderbuffer *proxy) = 0;
+
+ virtual GLenum getTarget() const = 0;
+
+ bool setMinFilter(GLenum filter);
+ bool setMagFilter(GLenum filter);
+ bool setWrapS(GLenum wrap);
+ bool setWrapT(GLenum wrap);
+ bool setMaxAnisotropy(float textureMaxAnisotropy, float contextMaxAnisotropy);
+ bool setUsage(GLenum usage);
+
+ GLenum getMinFilter() const;
+ GLenum getMagFilter() const;
+ GLenum getWrapS() const;
+ GLenum getWrapT() const;
+ float getMaxAnisotropy() const;
+ int getLodOffset();
+ void getSamplerState(SamplerState *sampler);
+ GLenum getUsage() const;
+ bool isMipmapFiltered() const;
+
+ virtual bool isSamplerComplete() const = 0;
+
+ rx::TextureStorageInterface *getNativeTexture();
+ virtual Renderbuffer *getRenderbuffer(GLenum target) = 0;
+
+ virtual void generateMipmaps() = 0;
+ virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0;
+
+ bool hasDirtyParameters() const;
+ bool hasDirtyImages() const;
+ void resetDirty();
+ unsigned int getTextureSerial();
+ unsigned int getRenderTargetSerial(GLenum target);
+
+ bool isImmutable() const;
+
+ static const GLuint INCOMPLETE_TEXTURE_ID = static_cast<GLuint>(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager.
+
+ protected:
+ void setImage(GLint unpackAlignment, const void *pixels, rx::Image *image);
+ bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, rx::Image *image);
+ void setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image);
+ bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image);
+
+ GLint creationLevels(GLsizei width, GLsizei height) const;
+ GLint creationLevels(GLsizei size) const;
+
+ virtual void createTexture() = 0;
+ virtual void updateTexture() = 0;
+ virtual void convertToRenderTarget() = 0;
+ virtual rx::RenderTarget *getRenderTarget(GLenum target) = 0;
+
+ virtual int levelCount() = 0;
+
+ rx::Renderer *mRenderer;
+
+ SamplerState mSamplerState;
+ GLenum mUsage;
+
+ bool mDirtyImages;
+
+ bool mImmutable;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Texture);
+
+ virtual rx::TextureStorageInterface *getStorage(bool renderTarget) = 0;
+};
+
+class Texture2D : public Texture
+{
+ public:
+ Texture2D(rx::Renderer *renderer, GLuint id);
+
+ ~Texture2D();
+
+ void addProxyRef(const Renderbuffer *proxy);
+ void releaseProxy(const Renderbuffer *proxy);
+
+ virtual GLenum getTarget() const;
+
+ GLsizei getWidth(GLint level) const;
+ GLsizei getHeight(GLint level) const;
+ GLenum getInternalFormat(GLint level) const;
+ GLenum getActualFormat(GLint level) const;
+ bool isCompressed(GLint level) const;
+ bool isDepth(GLint level) const;
+
+ void setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
+ void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
+ void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+ virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+ void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+
+ virtual bool isSamplerComplete() const;
+ virtual void bindTexImage(egl::Surface *surface);
+ virtual void releaseTexImage();
+
+ virtual void generateMipmaps();
+
+ virtual Renderbuffer *getRenderbuffer(GLenum target);
+
+ protected:
+ friend class RenderbufferTexture2D;
+ virtual rx::RenderTarget *getRenderTarget(GLenum target);
+ virtual rx::RenderTarget *getDepthStencil(GLenum target);
+ virtual int levelCount();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Texture2D);
+
+ virtual void createTexture();
+ virtual void updateTexture();
+ virtual void convertToRenderTarget();
+ virtual rx::TextureStorageInterface *getStorage(bool renderTarget);
+
+ bool isMipmapComplete() const;
+
+ void redefineImage(GLint level, GLint internalformat, GLsizei width, GLsizei height);
+ void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+
+ rx::Image *mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+
+ rx::TextureStorageInterface2D *mTexStorage;
+ egl::Surface *mSurface;
+
+ // A specific internal reference count is kept for colorbuffer proxy references,
+ // because, as the renderbuffer acting as proxy will maintain a binding pointer
+ // back to this texture, there would be a circular reference if we used a binding
+ // pointer here. This reference count will cause the pointer to be set to NULL if
+ // the count drops to zero, but will not cause deletion of the Renderbuffer.
+ Renderbuffer *mColorbufferProxy;
+ unsigned int mProxyRefs;
+};
+
+class TextureCubeMap : public Texture
+{
+ public:
+ TextureCubeMap(rx::Renderer *renderer, GLuint id);
+
+ ~TextureCubeMap();
+
+ void addProxyRef(const Renderbuffer *proxy);
+ void releaseProxy(const Renderbuffer *proxy);
+
+ virtual GLenum getTarget() const;
+
+ GLsizei getWidth(GLenum target, GLint level) const;
+ GLsizei getHeight(GLenum target, GLint level) const;
+ GLenum getInternalFormat(GLenum target, GLint level) const;
+ GLenum getActualFormat(GLenum target, GLint level) const;
+ bool isCompressed(GLenum target, GLint level) const;
+
+ void setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+
+ void setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
+
+ void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
+ void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+ virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+ void storage(GLsizei levels, GLenum internalformat, GLsizei size);
+
+ virtual bool isSamplerComplete() const;
+
+ virtual void generateMipmaps();
+
+ virtual Renderbuffer *getRenderbuffer(GLenum target);
+
+ static unsigned int faceIndex(GLenum face);
+
+ protected:
+ friend class RenderbufferTextureCubeMap;
+ virtual rx::RenderTarget *getRenderTarget(GLenum target);
+ virtual int levelCount();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureCubeMap);
+
+ virtual void createTexture();
+ virtual void updateTexture();
+ virtual void convertToRenderTarget();
+ virtual rx::TextureStorageInterface *getStorage(bool renderTarget);
+
+ bool isCubeComplete() const;
+ bool isMipmapCubeComplete() const;
+
+ void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+ void redefineImage(int faceIndex, GLint level, GLint internalformat, GLsizei width, GLsizei height);
+
+ rx::Image *mImageArray[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+
+ rx::TextureStorageInterfaceCube *mTexStorage;
+
+ // A specific internal reference count is kept for colorbuffer proxy references,
+ // because, as the renderbuffer acting as proxy will maintain a binding pointer
+ // back to this texture, there would be a circular reference if we used a binding
+ // pointer here. This reference count will cause the pointer to be set to NULL if
+ // the count drops to zero, but will not cause deletion of the Renderbuffer.
+ Renderbuffer *mFaceProxies[6];
+ unsigned int *mFaceProxyRefs[6];
+};
+}
+
+#endif // LIBGLESV2_TEXTURE_H_
diff --git a/src/libGLESv2/Uniform.cpp b/src/libGLESv2/Uniform.cpp
new file mode 100644
index 00000000..0fe3b8c9
--- /dev/null
+++ b/src/libGLESv2/Uniform.cpp
@@ -0,0 +1,43 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2010-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "libGLESv2/Uniform.h"
+
+#include "libGLESv2/utilities.h"
+
+namespace gl
+{
+
+Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize)
+ : type(type), precision(precision), name(name), arraySize(arraySize)
+{
+ int bytes = gl::UniformInternalSize(type) * elementCount();
+ data = new unsigned char[bytes];
+ memset(data, 0, bytes);
+ dirty = true;
+
+ psRegisterIndex = -1;
+ vsRegisterIndex = -1;
+ registerCount = VariableRowCount(type) * elementCount();
+}
+
+Uniform::~Uniform()
+{
+ delete[] data;
+}
+
+bool Uniform::isArray() const
+{
+ return arraySize > 0;
+}
+
+unsigned int Uniform::elementCount() const
+{
+ return arraySize > 0 ? arraySize : 1;
+}
+
+}
diff --git a/src/libGLESv2/Uniform.h b/src/libGLESv2/Uniform.h
new file mode 100644
index 00000000..64414acb
--- /dev/null
+++ b/src/libGLESv2/Uniform.h
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2010-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef LIBGLESV2_UNIFORM_H_
+#define LIBGLESV2_UNIFORM_H_
+
+#include <string>
+#include <vector>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "common/debug.h"
+
+namespace gl
+{
+
+// Helper struct representing a single shader uniform
+struct Uniform
+{
+ Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize);
+
+ ~Uniform();
+
+ bool isArray() const;
+ unsigned int elementCount() const;
+
+ const GLenum type;
+ const GLenum precision;
+ const std::string name;
+ const unsigned int arraySize;
+
+ unsigned char *data;
+ bool dirty;
+
+ int psRegisterIndex;
+ int vsRegisterIndex;
+ unsigned int registerCount;
+};
+
+typedef std::vector<Uniform*> UniformArray;
+
+}
+
+#endif // LIBGLESV2_UNIFORM_H_
diff --git a/src/libGLESv2/angletypes.h b/src/libGLESv2/angletypes.h
new file mode 100644
index 00000000..b2f0cad2
--- /dev/null
+++ b/src/libGLESv2/angletypes.h
@@ -0,0 +1,129 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2
+
+#ifndef LIBGLESV2_ANGLETYPES_H_
+#define LIBGLESV2_ANGLETYPES_H_
+
+namespace gl
+{
+
+enum TextureType
+{
+ TEXTURE_2D,
+ TEXTURE_CUBE,
+
+ TEXTURE_TYPE_COUNT,
+ TEXTURE_UNKNOWN
+};
+
+enum SamplerType
+{
+ SAMPLER_PIXEL,
+ SAMPLER_VERTEX
+};
+
+struct Color
+{
+ float red;
+ float green;
+ float blue;
+ float alpha;
+};
+
+struct Rectangle
+{
+ int x;
+ int y;
+ int width;
+ int height;
+};
+
+struct RasterizerState
+{
+ bool cullFace;
+ GLenum cullMode;
+ GLenum frontFace;
+
+ bool polygonOffsetFill;
+ GLfloat polygonOffsetFactor;
+ GLfloat polygonOffsetUnits;
+
+ bool pointDrawMode;
+ bool multiSample;
+};
+
+struct BlendState
+{
+ bool blend;
+ GLenum sourceBlendRGB;
+ GLenum destBlendRGB;
+ GLenum sourceBlendAlpha;
+ GLenum destBlendAlpha;
+ GLenum blendEquationRGB;
+ GLenum blendEquationAlpha;
+
+ bool colorMaskRed;
+ bool colorMaskGreen;
+ bool colorMaskBlue;
+ bool colorMaskAlpha;
+
+ bool sampleAlphaToCoverage;
+
+ bool dither;
+};
+
+struct DepthStencilState
+{
+ bool depthTest;
+ GLenum depthFunc;
+ bool depthMask;
+
+ bool stencilTest;
+ GLenum stencilFunc;
+ GLuint stencilMask;
+ GLenum stencilFail;
+ GLenum stencilPassDepthFail;
+ GLenum stencilPassDepthPass;
+ GLuint stencilWritemask;
+ GLenum stencilBackFunc;
+ GLuint stencilBackMask;
+ GLenum stencilBackFail;
+ GLenum stencilBackPassDepthFail;
+ GLenum stencilBackPassDepthPass;
+ GLuint stencilBackWritemask;
+};
+
+struct SamplerState
+{
+ GLenum minFilter;
+ GLenum magFilter;
+ GLenum wrapS;
+ GLenum wrapT;
+ float maxAnisotropy;
+ int lodOffset;
+};
+
+struct ClearParameters
+{
+ GLbitfield mask;
+
+ Color colorClearValue;
+ bool colorMaskRed;
+ bool colorMaskGreen;
+ bool colorMaskBlue;
+ bool colorMaskAlpha;
+
+ float depthClearValue;
+
+ GLint stencilClearValue;
+ GLuint stencilWriteMask;
+};
+
+}
+
+#endif // LIBGLESV2_ANGLETYPES_H_
diff --git a/src/libGLESv2/constants.h b/src/libGLESv2/constants.h
new file mode 100644
index 00000000..9f24d66a
--- /dev/null
+++ b/src/libGLESv2/constants.h
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Contants.h: Defines some implementation specific and gl constants
+
+#ifndef LIBGLESV2_CONSTANTS_H_
+#define LIBGLESV2_CONSTANTS_H_
+
+namespace gl
+{
+
+enum
+{
+ MAX_VERTEX_ATTRIBS = 16,
+ MAX_TEXTURE_IMAGE_UNITS = 16,
+
+ // Implementation upper limits, real maximums depend on the hardware
+ IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 16,
+ IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS = MAX_TEXTURE_IMAGE_UNITS + IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
+
+ IMPLEMENTATION_MAX_VARYING_VECTORS = 32,
+ IMPLEMENTATION_MAX_DRAW_BUFFERS = 8
+};
+
+const float ALIASED_LINE_WIDTH_RANGE_MIN = 1.0f;
+const float ALIASED_LINE_WIDTH_RANGE_MAX = 1.0f;
+const float ALIASED_POINT_SIZE_RANGE_MIN = 1.0f;
+
+}
+
+#endif // LIBGLESV2_CONSTANTS_H_
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
new file mode 100644
index 00000000..1e7cf9d0
--- /dev/null
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -0,0 +1,7106 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions.
+
+#include "common/version.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/Fence.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/Query.h"
+#include "libGLESv2/Context.h"
+
+bool validImageSize(GLint level, GLsizei width, GLsizei height)
+{
+ if (level < 0 || width < 0 || height < 0)
+ {
+ return false;
+ }
+
+ if (gl::getContext() && gl::getContext()->supportsNonPower2Texture())
+ {
+ return true;
+ }
+
+ if (level == 0)
+ {
+ return true;
+ }
+
+ if (gl::isPow2(width) && gl::isPow2(height))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Verify that format/type are one of the combinations from table 3.4.
+bool checkTextureFormatType(GLenum format, GLenum type)
+{
+ // validate <format> by itself (used as secondary key below)
+ switch (format)
+ {
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ case GL_RGB:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_STENCIL_OES:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM, false);
+ }
+
+ // invalid <type> -> sets INVALID_ENUM
+ // invalid <format>+<type> combination -> sets INVALID_OPERATION
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ switch (format)
+ {
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ case GL_RGB:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ return true;
+ default:
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ case GL_FLOAT:
+ case GL_HALF_FLOAT_OES:
+ switch (format)
+ {
+ case GL_RGBA:
+ case GL_RGB:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ return true;
+ default:
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ switch (format)
+ {
+ case GL_RGBA:
+ return true;
+ default:
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ case GL_UNSIGNED_SHORT_5_6_5:
+ switch (format)
+ {
+ case GL_RGB:
+ return true;
+ default:
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ case GL_UNSIGNED_SHORT:
+ case GL_UNSIGNED_INT:
+ switch (format)
+ {
+ case GL_DEPTH_COMPONENT:
+ return true;
+ default:
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ case GL_UNSIGNED_INT_24_8_OES:
+ switch (format)
+ {
+ case GL_DEPTH_STENCIL_OES:
+ return true;
+ default:
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ default:
+ return gl::error(GL_INVALID_ENUM, false);
+ }
+}
+
+bool validateSubImageParams2D(bool compressed, GLsizei width, GLsizei height,
+ GLint xoffset, GLint yoffset, GLint level, GLenum format, GLenum type,
+ gl::Texture2D *texture)
+{
+ if (!texture)
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ if (compressed != texture->isCompressed(level))
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ if (format != GL_NONE)
+ {
+ GLenum internalformat = gl::ConvertSizedInternalFormat(format, type);
+ if (internalformat != texture->getInternalFormat(level))
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+ }
+
+ if (compressed)
+ {
+ if ((width % 4 != 0 && width != texture->getWidth(0)) ||
+ (height % 4 != 0 && height != texture->getHeight(0)))
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+ }
+
+ if (xoffset + width > texture->getWidth(level) ||
+ yoffset + height > texture->getHeight(level))
+ {
+ return gl::error(GL_INVALID_VALUE, false);
+ }
+
+ return true;
+}
+
+bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height,
+ GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, GLenum type,
+ gl::TextureCubeMap *texture)
+{
+ if (!texture)
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ if (compressed != texture->isCompressed(target, level))
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+
+ if (format != GL_NONE)
+ {
+ GLenum internalformat = gl::ConvertSizedInternalFormat(format, type);
+ if (internalformat != texture->getInternalFormat(target, level))
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+ }
+
+ if (compressed)
+ {
+ if ((width % 4 != 0 && width != texture->getWidth(target, 0)) ||
+ (height % 4 != 0 && height != texture->getHeight(target, 0)))
+ {
+ return gl::error(GL_INVALID_OPERATION, false);
+ }
+ }
+
+ if (xoffset + width > texture->getWidth(target, level) ||
+ yoffset + height > texture->getHeight(target, level))
+ {
+ return gl::error(GL_INVALID_VALUE, false);
+ }
+
+ return true;
+}
+
+// check for combinations of format and type that are valid for ReadPixels
+bool validReadFormatType(GLenum format, GLenum type)
+{
+ switch (format)
+ {
+ case GL_RGBA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ break;
+ default:
+ return false;
+ }
+ break;
+ case GL_BGRA_EXT:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
+ break;
+ default:
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+extern "C"
+{
+
+void __stdcall glActiveTexture(GLenum texture)
+{
+ EVENT("(GLenum texture = 0x%X)", texture);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getMaximumCombinedTextureImageUnits() - 1)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ context->setActiveSampler(texture - GL_TEXTURE0);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glAttachShader(GLuint program, GLuint shader)
+{
+ EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (!shaderObject)
+ {
+ if (context->getProgram(shader))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (!programObject->attachShader(shaderObject))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBeginQueryEXT(GLenum target, GLuint id)
+{
+ EVENT("(GLenum target = 0x%X, GLuint %d)", target, id);
+
+ try
+ {
+ switch (target)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (id == 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->beginQuery(target, id);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
+{
+ EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (strncmp(name, "gl_", 3) == 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ programObject->bindAttributeLocation(index, name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindBuffer(GLenum target, GLuint buffer)
+{
+ EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER:
+ context->bindArrayBuffer(buffer);
+ return;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ context->bindElementArrayBuffer(buffer);
+ return;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer)
+{
+ EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer);
+
+ try
+ {
+ if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
+ {
+ context->bindReadFramebuffer(framebuffer);
+ }
+
+ if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
+ {
+ context->bindDrawFramebuffer(framebuffer);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+ EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer);
+
+ try
+ {
+ if (target != GL_RENDERBUFFER)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->bindRenderbuffer(renderbuffer);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindTexture(GLenum target, GLuint texture)
+{
+ EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Texture *textureObject = context->getTexture(texture);
+
+ if (textureObject && textureObject->getTarget() != target && texture != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ context->bindTexture2D(texture);
+ return;
+ case GL_TEXTURE_CUBE_MAP:
+ context->bindTextureCubeMap(texture);
+ return;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+ EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
+ red, green, blue, alpha);
+
+ try
+ {
+ gl::Context* context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha));
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBlendEquation(GLenum mode)
+{
+ glBlendEquationSeparate(mode, mode);
+}
+
+void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+{
+ EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha);
+
+ try
+ {
+ switch (modeRGB)
+ {
+ case GL_FUNC_ADD:
+ case GL_FUNC_SUBTRACT:
+ case GL_FUNC_REVERSE_SUBTRACT:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (modeAlpha)
+ {
+ case GL_FUNC_ADD:
+ case GL_FUNC_SUBTRACT:
+ case GL_FUNC_REVERSE_SUBTRACT:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setBlendEquation(modeRGB, modeAlpha);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+ glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);
+}
+
+void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+ EVENT("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)",
+ srcRGB, dstRGB, srcAlpha, dstAlpha);
+
+ try
+ {
+ switch (srcRGB)
+ {
+ 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:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (dstRGB)
+ {
+ 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:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (srcAlpha)
+ {
+ 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:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (dstAlpha)
+ {
+ 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:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ 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)
+ {
+ ERR("Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR invalid under WebGL");
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+ EVENT("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)",
+ target, size, data, usage);
+
+ try
+ {
+ if (size < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ switch (usage)
+ {
+ case GL_STREAM_DRAW:
+ case GL_STATIC_DRAW:
+ case GL_DYNAMIC_DRAW:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Buffer *buffer;
+
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER:
+ buffer = context->getArrayBuffer();
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ buffer = context->getElementArrayBuffer();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (!buffer)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ buffer->bufferData(data, size, usage);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+ EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)",
+ target, offset, size, data);
+
+ try
+ {
+ if (size < 0 || offset < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (data == NULL)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Buffer *buffer;
+
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER:
+ buffer = context->getArrayBuffer();
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ buffer = context->getElementArrayBuffer();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (!buffer)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if ((size_t)size + offset > buffer->size())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ buffer->bufferSubData(data, size, offset);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLenum __stdcall glCheckFramebufferStatus(GLenum target)
+{
+ EVENT("(GLenum target = 0x%X)", target);
+
+ try
+ {
+ if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ return gl::error(GL_INVALID_ENUM, 0);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Framebuffer *framebuffer = NULL;
+ if (target == GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ framebuffer = context->getReadFramebuffer();
+ }
+ else
+ {
+ framebuffer = context->getDrawFramebuffer();
+ }
+
+ return framebuffer->completeness();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, 0);
+ }
+
+ return 0;
+}
+
+void __stdcall glClear(GLbitfield mask)
+{
+ EVENT("(GLbitfield mask = %X)", mask);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->clear(mask);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+ EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
+ red, green, blue, alpha);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setClearColor(red, green, blue, alpha);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glClearDepthf(GLclampf depth)
+{
+ EVENT("(GLclampf depth = %f)", depth);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setClearDepth(depth);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glClearStencil(GLint s)
+{
+ EVENT("(GLint s = %d)", s);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setClearStencil(s);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+ EVENT("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)",
+ red, green, blue, alpha);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCompileShader(GLuint shader)
+{
+ EVENT("(GLuint shader = %d)", shader);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ if (context->getProgram(shader))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ shaderObject->compile();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
+ GLint border, GLsizei imageSize, const GLvoid* data)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
+ "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
+ target, level, internalformat, width, height, border, imageSize, data);
+
+ try
+ {
+ if (!validImageSize(level, width, height) || border != 0 || imageSize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ 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:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (border != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (width != 1 && width != 2 && width % 4 != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (height != 1 && height != 2 && height % 4 != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ if (width > (context->getMaximumTextureDimension() >> level) ||
+ height > (context->getMaximumTextureDimension() >> level))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ 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 (width != height)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (width > (context->getMaximumCubeTextureDimension() >> level) ||
+ height > (context->getMaximumCubeTextureDimension() >> level))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (internalformat) {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ if (!context->supportsDXT1Textures())
+ {
+ return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ if (!context->supportsDXT3Textures())
+ {
+ return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ if (!context->supportsDXT5Textures())
+ {
+ return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ if (imageSize != gl::ComputeCompressedSize(width, height, internalformat))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if (!texture)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (texture->isImmutable())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ texture->setCompressedImage(level, internalformat, width, height, imageSize, data);
+ }
+ else
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if (!texture)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (texture->isImmutable())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ switch (target)
+ {
+ 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:
+ texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize, const GLvoid* data)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, "
+ "GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
+ target, level, xoffset, yoffset, width, height, format, imageSize, data);
+
+ try
+ {
+ if (!gl::IsInternalTextureTarget(target))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height) || imageSize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ switch (format)
+ {
+ 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:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (width == 0 || height == 0 || data == NULL)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ switch (format) {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ if (!context->supportsDXT1Textures())
+ {
+ return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ if (!context->supportsDXT3Textures())
+ {
+ return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ if (!context->supportsDXT5Textures())
+ {
+ return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ if (imageSize != gl::ComputeCompressedSize(width, height, format))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (xoffset % 4 != 0 || yoffset % 4 != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION); // we wait to check the offsets until this point, because the multiple-of-four restriction
+ // does not exist unless DXT textures are supported.
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+ if (validateSubImageParams2D(true, width, height, xoffset, yoffset, level, format, GL_NONE, texture))
+ {
+ texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
+ }
+ }
+ else if (gl::IsCubemapTextureTarget(target))
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+ if (validateSubImageParamsCube(true, width, height, xoffset, yoffset, target, level, format, GL_NONE, texture))
+ {
+ texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
+ "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)",
+ target, level, internalformat, x, y, width, height, border);
+
+ try
+ {
+ if (!validImageSize(level, width, height))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (border != 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ if (width > (context->getMaximumTextureDimension() >> level) ||
+ height > (context->getMaximumTextureDimension() >> level))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ 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 (width != height)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (width > (context->getMaximumCubeTextureDimension() >> level) ||
+ height > (context->getMaximumCubeTextureDimension() >> level))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Framebuffer *framebuffer = context->getReadFramebuffer();
+
+ if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
+ GLenum colorbufferFormat = source->getInternalFormat();
+
+ // [OpenGL ES 2.0.24] table 3.9
+ 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)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_LUMINANCE:
+ 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)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ if (colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_BGRA8_EXT &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ if (context->supportsDXT1Textures())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ if (context->supportsDXT3Textures())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ if (context->supportsDXT5Textures())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ 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->supportsDepthTextures())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if (!texture)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (texture->isImmutable())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ texture->copyImage(level, internalformat, x, y, width, height, framebuffer);
+ }
+ else if (gl::IsCubemapTextureTarget(target))
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if (!texture)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (texture->isImmutable())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer);
+ }
+ else UNREACHABLE();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
+ target, level, xoffset, yoffset, x, y, width, height);
+
+ try
+ {
+ if (!gl::IsInternalTextureTarget(target))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (width == 0 || height == 0)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Framebuffer *framebuffer = context->getReadFramebuffer();
+
+ if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
+ GLenum colorbufferFormat = source->getInternalFormat();
+ gl::Texture *texture = NULL;
+ GLenum textureFormat = GL_RGBA;
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *tex2d = context->getTexture2D();
+
+ if (!validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d))
+ {
+ return; // error already registered by validateSubImageParams
+ }
+ textureFormat = gl::ExtractFormat(tex2d->getInternalFormat(level));
+ texture = tex2d;
+ }
+ else if (gl::IsCubemapTextureTarget(target))
+ {
+ gl::TextureCubeMap *texcube = context->getTextureCubeMap();
+
+ if (!validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube))
+ {
+ return; // error already registered by validateSubImageParams
+ }
+ textureFormat = gl::ExtractFormat(texcube->getInternalFormat(target, level));
+ texture = texcube;
+ }
+ else UNREACHABLE();
+
+ // [OpenGL ES 2.0.24] table 3.9
+ switch (textureFormat)
+ {
+ case GL_ALPHA:
+ if (colorbufferFormat != GL_ALPHA8_EXT &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_LUMINANCE:
+ case GL_RGB:
+ if (colorbufferFormat != GL_RGB565 &&
+ colorbufferFormat != GL_RGB8_OES &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ if (colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ 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:
+ return gl::error(GL_INVALID_OPERATION);
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_STENCIL_OES:
+ return gl::error(GL_INVALID_OPERATION);
+ default:
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer);
+ }
+ }
+
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLuint __stdcall glCreateProgram(void)
+{
+ EVENT("()");
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ return context->createProgram();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, 0);
+ }
+
+ return 0;
+}
+
+GLuint __stdcall glCreateShader(GLenum type)
+{
+ EVENT("(GLenum type = 0x%X)", type);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (type)
+ {
+ case GL_FRAGMENT_SHADER:
+ case GL_VERTEX_SHADER:
+ return context->createShader(type);
+ default:
+ return gl::error(GL_INVALID_ENUM, 0);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, 0);
+ }
+
+ return 0;
+}
+
+void __stdcall glCullFace(GLenum mode)
+{
+ EVENT("(GLenum mode = 0x%X)", mode);
+
+ try
+ {
+ switch (mode)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setCullMode(mode);
+ }
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+ EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ context->deleteBuffer(buffers[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences)
+{
+ EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ context->deleteFence(fences[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+{
+ EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ if (framebuffers[i] != 0)
+ {
+ context->deleteFramebuffer(framebuffers[i]);
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ if (program == 0)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (!context->getProgram(program))
+ {
+ if(context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ context->deleteProgram(program);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteQueriesEXT(GLsizei n, const GLuint *ids)
+{
+ EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ context->deleteQuery(ids[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+{
+ EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ context->deleteRenderbuffer(renderbuffers[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteShader(GLuint shader)
+{
+ EVENT("(GLuint shader = %d)", shader);
+
+ try
+ {
+ if (shader == 0)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (!context->getShader(shader))
+ {
+ if(context->getProgram(shader))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ context->deleteShader(shader);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures)
+{
+ EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ if (textures[i] != 0)
+ {
+ context->deleteTexture(textures[i]);
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDepthFunc(GLenum func)
+{
+ EVENT("(GLenum func = 0x%X)", func);
+
+ try
+ {
+ 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:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setDepthFunc(func);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDepthMask(GLboolean flag)
+{
+ EVENT("(GLboolean flag = %d)", flag);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setDepthMask(flag != GL_FALSE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar)
+{
+ EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setDepthRange(zNear, zFar);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDetachShader(GLuint program, GLuint shader)
+{
+ EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+
+ gl::Program *programObject = context->getProgram(program);
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!programObject)
+ {
+ gl::Shader *shaderByProgramHandle;
+ shaderByProgramHandle = context->getShader(program);
+ if (!shaderByProgramHandle)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+
+ if (!shaderObject)
+ {
+ gl::Program *programByShaderHandle = context->getProgram(shader);
+ if (!programByShaderHandle)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+
+ if (!programObject->detachShader(shaderObject))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDisable(GLenum cap)
+{
+ EVENT("(GLenum cap = 0x%X)", cap);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (cap)
+ {
+ case GL_CULL_FACE: context->setCullFace(false); break;
+ case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(false); break;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(false); break;
+ case GL_SAMPLE_COVERAGE: context->setSampleCoverage(false); break;
+ case GL_SCISSOR_TEST: context->setScissorTest(false); break;
+ case GL_STENCIL_TEST: context->setStencilTest(false); break;
+ case GL_DEPTH_TEST: context->setDepthTest(false); break;
+ case GL_BLEND: context->setBlend(false); break;
+ case GL_DITHER: context->setDither(false); break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDisableVertexAttribArray(GLuint index)
+{
+ EVENT("(GLuint index = %d)", index);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setEnableVertexAttribArray(index, false);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+ EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count);
+
+ try
+ {
+ if (count < 0 || first < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->drawArrays(mode, first, count, 0);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
+{
+ EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei primcount = %d)", mode, first, count, primcount);
+
+ try
+ {
+ if (count < 0 || first < 0 || primcount < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (primcount > 0)
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->drawArrays(mode, first, count, primcount);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+{
+ EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)",
+ mode, count, type, indices);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT:
+ break;
+ case GL_UNSIGNED_INT:
+ if (!context->supports32bitIndices())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ context->drawElements(mode, count, type, indices, 0);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount)
+{
+ EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei primcount = %d)",
+ mode, count, type, indices, primcount);
+
+ try
+ {
+ if (count < 0 || primcount < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (primcount > 0)
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT:
+ break;
+ case GL_UNSIGNED_INT:
+ if (!context->supports32bitIndices())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ context->drawElements(mode, count, type, indices, primcount);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glEnable(GLenum cap)
+{
+ EVENT("(GLenum cap = 0x%X)", cap);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (cap)
+ {
+ case GL_CULL_FACE: context->setCullFace(true); break;
+ case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(true); break;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(true); break;
+ case GL_SAMPLE_COVERAGE: context->setSampleCoverage(true); break;
+ case GL_SCISSOR_TEST: context->setScissorTest(true); break;
+ case GL_STENCIL_TEST: context->setStencilTest(true); break;
+ case GL_DEPTH_TEST: context->setDepthTest(true); break;
+ case GL_BLEND: context->setBlend(true); break;
+ case GL_DITHER: context->setDither(true); break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glEnableVertexAttribArray(GLuint index)
+{
+ EVENT("(GLuint index = %d)", index);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setEnableVertexAttribArray(index, true);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glEndQueryEXT(GLenum target)
+{
+ EVENT("GLenum target = 0x%X)", target);
+
+ try
+ {
+ switch (target)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->endQuery(target);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFinishFenceNV(GLuint fence)
+{
+ EVENT("(GLuint fence = %d)", fence);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Fence* fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ fenceObject->finishFence();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFinish(void)
+{
+ EVENT("()");
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->sync(true);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFlush(void)
+{
+ EVENT("()");
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->sync(false);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+ EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, "
+ "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer);
+
+ try
+ {
+ if ((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Framebuffer *framebuffer = NULL;
+ GLuint framebufferHandle = 0;
+ if (target == GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ framebuffer = context->getReadFramebuffer();
+ framebufferHandle = context->getReadFramebufferHandle();
+ }
+ else
+ {
+ framebuffer = context->getDrawFramebuffer();
+ framebufferHandle = context->getDrawFramebufferHandle();
+ }
+
+ if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
+ {
+ const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+
+ if (colorAttachment >= context->getMaximumRenderTargets())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ framebuffer->setColorbuffer(colorAttachment, GL_RENDERBUFFER, renderbuffer);
+ }
+ else
+ {
+ switch (attachment)
+ {
+ case GL_DEPTH_ATTACHMENT:
+ framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer);
+ break;
+ case GL_STENCIL_ATTACHMENT:
+ framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer);
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+ EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, "
+ "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level);
+
+ try
+ {
+ if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
+ {
+ const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+
+ if (colorAttachment >= context->getMaximumRenderTargets())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+ else
+ {
+ switch (attachment)
+ {
+ case GL_DEPTH_ATTACHMENT:
+ case GL_STENCIL_ATTACHMENT:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+
+ if (texture == 0)
+ {
+ textarget = GL_NONE;
+ }
+ else
+ {
+ gl::Texture *tex = context->getTexture(texture);
+
+ if (tex == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ switch (textarget)
+ {
+ case GL_TEXTURE_2D:
+ {
+ if (tex->getTarget() != GL_TEXTURE_2D)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
+ if (tex2d->isCompressed(0))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ 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 (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
+ if (texcube->isCompressed(textarget, level))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ }
+
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (level != 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ gl::Framebuffer *framebuffer = NULL;
+ GLuint framebufferHandle = 0;
+ if (target == GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ framebuffer = context->getReadFramebuffer();
+ framebufferHandle = context->getReadFramebufferHandle();
+ }
+ else
+ {
+ framebuffer = context->getDrawFramebuffer();
+ framebufferHandle = context->getDrawFramebufferHandle();
+ }
+
+ if (framebufferHandle == 0 || !framebuffer)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
+ {
+ const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+
+ if (colorAttachment >= context->getMaximumRenderTargets())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ framebuffer->setColorbuffer(colorAttachment, textarget, texture);
+ }
+ else
+ {
+ switch (attachment)
+ {
+ case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture); break;
+ case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture); break;
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFrontFace(GLenum mode)
+{
+ EVENT("(GLenum mode = 0x%X)", mode);
+
+ try
+ {
+ switch (mode)
+ {
+ case GL_CW:
+ case GL_CCW:
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setFrontFace(mode);
+ }
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenBuffers(GLsizei n, GLuint* buffers)
+{
+ EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ buffers[i] = context->createBuffer();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenerateMipmap(GLenum target)
+{
+ EVENT("(GLenum target = 0x%X)", target);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ {
+ gl::Texture2D *tex2d = context->getTexture2D();
+
+ if (tex2d->isCompressed(0))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ if (tex2d->isDepth(0))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ tex2d->generateMipmaps();
+ break;
+ }
+
+ case GL_TEXTURE_CUBE_MAP:
+ {
+ gl::TextureCubeMap *texcube = context->getTextureCubeMap();
+
+ if (texcube->isCompressed(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ texcube->generateMipmaps();
+ break;
+ }
+
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenFencesNV(GLsizei n, GLuint* fences)
+{
+ EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ fences[i] = context->createFence();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers)
+{
+ EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ framebuffers[i] = context->createFramebuffer();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenQueriesEXT(GLsizei n, GLuint* ids)
+{
+ EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ ids[i] = context->createQuery();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+{
+ EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ renderbuffers[i] = context->createRenderbuffer();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenTextures(GLsizei n, GLuint* textures)
+{
+ EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures);
+
+ try
+ {
+ if (n < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ textures[i] = context->createTexture();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+ EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = 0x%0.8p, "
+ "GLint *size = 0x%0.8p, GLenum *type = %0.8p, GLchar *name = %0.8p)",
+ program, index, bufsize, length, size, type, name);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (index >= (GLuint)programObject->getActiveAttributeCount())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ programObject->getActiveAttribute(index, bufsize, length, size, type, name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+ EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, "
+ "GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)",
+ program, index, bufsize, length, size, type, name);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (index >= (GLuint)programObject->getActiveUniformCount())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ programObject->getActiveUniform(index, bufsize, length, size, type, name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+ EVENT("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)",
+ program, maxcount, count, shaders);
+
+ try
+ {
+ if (maxcount < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ return programObject->getAttachedShaders(maxcount, count, shaders);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+int __stdcall glGetAttribLocation(GLuint program, const GLchar* name)
+{
+ EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION, -1);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE, -1);
+ }
+ }
+
+ gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+ if (!programObject->isLinked() || !programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION, -1);
+ }
+
+ return programBinary->getAttributeLocation(name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, -1);
+ }
+
+ return -1;
+}
+
+void __stdcall glGetBooleanv(GLenum pname, GLboolean* params)
+{
+ EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (!(context->getBooleanv(pname, params)))
+ {
+ GLenum nativeType;
+ unsigned int numParams = 0;
+ if (!context->getQueryParameterInfo(pname, &nativeType, &numParams))
+ return gl::error(GL_INVALID_ENUM);
+
+ if (numParams == 0)
+ return; // it is known that the pname is valid, but there are no parameters to return
+
+ if (nativeType == GL_FLOAT)
+ {
+ GLfloat *floatParams = NULL;
+ floatParams = new GLfloat[numParams];
+
+ context->getFloatv(pname, floatParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (floatParams[i] == 0.0f)
+ params[i] = GL_FALSE;
+ else
+ params[i] = GL_TRUE;
+ }
+
+ delete [] floatParams;
+ }
+ else if (nativeType == GL_INT)
+ {
+ GLint *intParams = NULL;
+ intParams = new GLint[numParams];
+
+ context->getIntegerv(pname, intParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (intParams[i] == 0)
+ params[i] = GL_FALSE;
+ else
+ params[i] = GL_TRUE;
+ }
+
+ delete [] intParams;
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Buffer *buffer;
+
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER:
+ buffer = context->getArrayBuffer();
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ buffer = context->getElementArrayBuffer();
+ break;
+ default: return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (!buffer)
+ {
+ // A null buffer means that "0" is bound to the requested buffer target
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ switch (pname)
+ {
+ case GL_BUFFER_USAGE:
+ *params = buffer->usage();
+ break;
+ case GL_BUFFER_SIZE:
+ *params = buffer->size();
+ break;
+ default: return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLenum __stdcall glGetError(void)
+{
+ EVENT("()");
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ return context->getError();
+ }
+
+ return GL_NO_ERROR;
+}
+
+void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params)
+{
+ EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params);
+
+ try
+ {
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Fence *fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ fenceObject->getFenceiv(pname, params);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetFloatv(GLenum pname, GLfloat* params)
+{
+ EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (!(context->getFloatv(pname, params)))
+ {
+ GLenum nativeType;
+ unsigned int numParams = 0;
+ if (!context->getQueryParameterInfo(pname, &nativeType, &numParams))
+ return gl::error(GL_INVALID_ENUM);
+
+ if (numParams == 0)
+ return; // it is known that the pname is valid, but that there are no parameters to return.
+
+ if (nativeType == GL_BOOL)
+ {
+ GLboolean *boolParams = NULL;
+ boolParams = new GLboolean[numParams];
+
+ context->getBooleanv(pname, boolParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (boolParams[i] == GL_FALSE)
+ params[i] = 0.0f;
+ else
+ params[i] = 1.0f;
+ }
+
+ delete [] boolParams;
+ }
+ else if (nativeType == GL_INT)
+ {
+ GLint *intParams = NULL;
+ intParams = new GLint[numParams];
+
+ context->getIntegerv(pname, intParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ params[i] = (GLfloat)intParams[i];
+ }
+
+ delete [] intParams;
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)",
+ target, attachment, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Framebuffer *framebuffer = NULL;
+ if (target == GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ if(context->getReadFramebufferHandle() == 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ framebuffer = context->getReadFramebuffer();
+ }
+ else
+ {
+ if (context->getDrawFramebufferHandle() == 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ framebuffer = context->getDrawFramebuffer();
+ }
+
+ GLenum attachmentType;
+ GLuint attachmentHandle;
+
+ if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
+ {
+ const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT);
+
+ if (colorAttachment >= context->getMaximumRenderTargets())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ attachmentType = framebuffer->getColorbufferType(colorAttachment);
+ attachmentHandle = framebuffer->getColorbufferHandle(colorAttachment);
+ }
+ else
+ {
+ switch (attachment)
+ {
+ case GL_DEPTH_ATTACHMENT:
+ attachmentType = framebuffer->getDepthbufferType();
+ attachmentHandle = framebuffer->getDepthbufferHandle();
+ break;
+ case GL_STENCIL_ATTACHMENT:
+ attachmentType = framebuffer->getStencilbufferType();
+ attachmentHandle = framebuffer->getStencilbufferHandle();
+ break;
+ default: return gl::error(GL_INVALID_ENUM);
+ }
+ }
+
+ GLenum attachmentObjectType; // Type category
+ if (attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER)
+ {
+ attachmentObjectType = attachmentType;
+ }
+ else if (gl::IsInternalTextureTarget(attachmentType))
+ {
+ attachmentObjectType = GL_TEXTURE;
+ }
+ else
+ {
+ UNREACHABLE();
+ return;
+ }
+
+ switch (pname)
+ {
+ case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ *params = attachmentObjectType;
+ break;
+ case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ if (attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE)
+ {
+ *params = attachmentHandle;
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+ if (attachmentObjectType == GL_TEXTURE)
+ {
+ *params = 0; // FramebufferTexture2D will not allow level to be set to anything else in GL ES 2.0
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+ if (attachmentObjectType == GL_TEXTURE)
+ {
+ if (gl::IsCubemapTextureTarget(attachmentType))
+ {
+ *params = attachmentType;
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLenum __stdcall glGetGraphicsResetStatusEXT(void)
+{
+ EVENT("()");
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ return context->getResetStatus();
+ }
+
+ return GL_NO_ERROR;
+ }
+ catch(std::bad_alloc&)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+}
+
+void __stdcall glGetIntegerv(GLenum pname, GLint* params)
+{
+ EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (!(context->getIntegerv(pname, params)))
+ {
+ GLenum nativeType;
+ unsigned int numParams = 0;
+ if (!context->getQueryParameterInfo(pname, &nativeType, &numParams))
+ return gl::error(GL_INVALID_ENUM);
+
+ if (numParams == 0)
+ return; // it is known that pname is valid, but there are no parameters to return
+
+ if (nativeType == GL_BOOL)
+ {
+ GLboolean *boolParams = NULL;
+ boolParams = new GLboolean[numParams];
+
+ context->getBooleanv(pname, boolParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (boolParams[i] == GL_FALSE)
+ params[i] = 0;
+ else
+ params[i] = 1;
+ }
+
+ delete [] boolParams;
+ }
+ else if (nativeType == GL_FLOAT)
+ {
+ GLfloat *floatParams = NULL;
+ floatParams = new GLfloat[numParams];
+
+ context->getFloatv(pname, floatParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
+ {
+ params[i] = (GLint)(((GLfloat)(0xFFFFFFFF) * floatParams[i] - 1.0f) / 2.0f);
+ }
+ else
+ params[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
+ }
+
+ delete [] floatParams;
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params)
+{
+ EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ switch (pname)
+ {
+ case GL_DELETE_STATUS:
+ *params = programObject->isFlaggedForDeletion();
+ return;
+ case GL_LINK_STATUS:
+ *params = programObject->isLinked();
+ return;
+ case GL_VALIDATE_STATUS:
+ *params = programObject->isValidated();
+ return;
+ case GL_INFO_LOG_LENGTH:
+ *params = programObject->getInfoLogLength();
+ return;
+ case GL_ATTACHED_SHADERS:
+ *params = programObject->getAttachedShadersCount();
+ return;
+ case GL_ACTIVE_ATTRIBUTES:
+ *params = programObject->getActiveAttributeCount();
+ return;
+ case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = programObject->getActiveAttributeMaxLength();
+ return;
+ case GL_ACTIVE_UNIFORMS:
+ *params = programObject->getActiveUniformCount();
+ return;
+ case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+ *params = programObject->getActiveUniformMaxLength();
+ return;
+ case GL_PROGRAM_BINARY_LENGTH_OES:
+ *params = programObject->getProgramBinaryLength();
+ return;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+ EVENT("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",
+ program, bufsize, length, infolog);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ programObject->getInfoLog(bufsize, length, infolog);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetQueryivEXT(GLenum target, GLenum pname, GLint *params)
+{
+ EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ switch (pname)
+ {
+ case GL_CURRENT_QUERY_EXT:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ params[0] = context->getActiveQuery(target);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params)
+{
+ EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params);
+
+ try
+ {
+ switch (pname)
+ {
+ case GL_QUERY_RESULT_EXT:
+ case GL_QUERY_RESULT_AVAILABLE_EXT:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Query *queryObject = context->getQuery(id, false, GL_NONE);
+
+ if (!queryObject)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (context->getActiveQuery(queryObject->getType()) == id)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ switch(pname)
+ {
+ case GL_QUERY_RESULT_EXT:
+ params[0] = queryObject->getResult();
+ break;
+ case GL_QUERY_RESULT_AVAILABLE_EXT:
+ params[0] = queryObject->isResultAvailable();
+ break;
+ default:
+ ASSERT(false);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (target != GL_RENDERBUFFER)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (context->getRenderbufferHandle() == 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getRenderbufferHandle());
+
+ switch (pname)
+ {
+ case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break;
+ case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break;
+ case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); 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:
+ if (context->getMaxSupportedSamples() != 0)
+ {
+ *params = renderbuffer->getSamples();
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+{
+ EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ switch (pname)
+ {
+ case GL_SHADER_TYPE:
+ *params = shaderObject->getType();
+ return;
+ case GL_DELETE_STATUS:
+ *params = shaderObject->isFlaggedForDeletion();
+ return;
+ case GL_COMPILE_STATUS:
+ *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE;
+ return;
+ case GL_INFO_LOG_LENGTH:
+ *params = shaderObject->getInfoLogLength();
+ return;
+ case GL_SHADER_SOURCE_LENGTH:
+ *params = shaderObject->getSourceLength();
+ return;
+ case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
+ *params = shaderObject->getTranslatedSourceLength();
+ return;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+ EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",
+ shader, bufsize, length, infolog);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ shaderObject->getInfoLog(bufsize, length, infolog);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+ EVENT("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)",
+ shadertype, precisiontype, range, precision);
+
+ try
+ {
+ switch (shadertype)
+ {
+ case GL_VERTEX_SHADER:
+ case GL_FRAGMENT_SHADER:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (precisiontype)
+ {
+ case GL_LOW_FLOAT:
+ case GL_MEDIUM_FLOAT:
+ case GL_HIGH_FLOAT:
+ // Assume IEEE 754 precision
+ range[0] = 127;
+ range[1] = 127;
+ *precision = 23;
+ break;
+ case GL_LOW_INT:
+ case GL_MEDIUM_INT:
+ case GL_HIGH_INT:
+ // Some (most) hardware only supports single-precision floating-point numbers,
+ // which can accurately represent integers up to +/-16777216
+ range[0] = 24;
+ range[1] = 24;
+ *precision = 0;
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+{
+ EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)",
+ shader, bufsize, length, source);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ shaderObject->getSource(bufsize, length, source);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+{
+ EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)",
+ shader, bufsize, length, source);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ shaderObject->getTranslatedSource(bufsize, length, source);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+const GLubyte* __stdcall glGetString(GLenum name)
+{
+ EVENT("(GLenum name = 0x%X)", name);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ switch (name)
+ {
+ case GL_VENDOR:
+ return (GLubyte*)"Google Inc.";
+ case GL_RENDERER:
+ return (GLubyte*)((context != NULL) ? context->getRendererString() : "ANGLE");
+ case GL_VERSION:
+ return (GLubyte*)"OpenGL ES 2.0 (ANGLE " VERSION_STRING ")";
+ case GL_SHADING_LANGUAGE_VERSION:
+ return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE " VERSION_STRING ")";
+ case GL_EXTENSIONS:
+ return (GLubyte*)((context != NULL) ? context->getExtensionString() : "");
+ default:
+ return gl::error(GL_INVALID_ENUM, (GLubyte*)NULL);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, (GLubyte*)NULL);
+ }
+}
+
+void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Texture *texture;
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (pname)
+ {
+ case GL_TEXTURE_MAG_FILTER:
+ *params = (GLfloat)texture->getMagFilter();
+ break;
+ case GL_TEXTURE_MIN_FILTER:
+ *params = (GLfloat)texture->getMinFilter();
+ break;
+ case GL_TEXTURE_WRAP_S:
+ *params = (GLfloat)texture->getWrapS();
+ break;
+ case GL_TEXTURE_WRAP_T:
+ *params = (GLfloat)texture->getWrapT();
+ break;
+ case GL_TEXTURE_IMMUTABLE_FORMAT_EXT:
+ *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE);
+ break;
+ case GL_TEXTURE_USAGE_ANGLE:
+ *params = (GLfloat)texture->getUsage();
+ break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+ if (!context->supportsTextureFilterAnisotropy())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ *params = (GLfloat)texture->getMaxAnisotropy();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Texture *texture;
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (pname)
+ {
+ case GL_TEXTURE_MAG_FILTER:
+ *params = texture->getMagFilter();
+ break;
+ case GL_TEXTURE_MIN_FILTER:
+ *params = texture->getMinFilter();
+ break;
+ case GL_TEXTURE_WRAP_S:
+ *params = texture->getWrapS();
+ break;
+ case GL_TEXTURE_WRAP_T:
+ *params = texture->getWrapT();
+ break;
+ case GL_TEXTURE_IMMUTABLE_FORMAT_EXT:
+ *params = texture->isImmutable() ? GL_TRUE : GL_FALSE;
+ break;
+ case GL_TEXTURE_USAGE_ANGLE:
+ *params = texture->getUsage();
+ break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+ if (!context->supportsTextureFilterAnisotropy())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ *params = (GLint)texture->getMaxAnisotropy();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
+{
+ EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)",
+ program, location, bufSize, params);
+
+ try
+ {
+ if (bufSize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (program == 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject || !programObject->isLinked())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->getUniformfv(location, &bufSize, params))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+ EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (program == 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject || !programObject->isLinked())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->getUniformfv(location, NULL, params))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params)
+{
+ EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)",
+ program, location, bufSize, params);
+
+ try
+ {
+ if (bufSize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (program == 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject || !programObject->isLinked())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->getUniformiv(location, &bufSize, params))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params)
+{
+ EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (program == 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject || !programObject->isLinked())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->getUniformiv(location, NULL, params))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+int __stdcall glGetUniformLocation(GLuint program, const GLchar* name)
+{
+ EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (strstr(name, "gl_") == name)
+ {
+ return -1;
+ }
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION, -1);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE, -1);
+ }
+ }
+
+ gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+ if (!programObject->isLinked() || !programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION, -1);
+ }
+
+ return programBinary->getUniformLocation(name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, -1);
+ }
+
+ return -1;
+}
+
+void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+{
+ EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
+
+ switch (pname)
+ {
+ case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+ *params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+ *params = (GLfloat)attribState.mSize;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+ *params = (GLfloat)attribState.mStride;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+ *params = (GLfloat)attribState.mType;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+ *params = (GLfloat)(attribState.mNormalized ? GL_TRUE : GL_FALSE);
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+ *params = (GLfloat)attribState.mBoundBuffer.id();
+ break;
+ case GL_CURRENT_VERTEX_ATTRIB:
+ for (int i = 0; i < 4; ++i)
+ {
+ params[i] = attribState.mCurrentValue[i];
+ }
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE:
+ *params = (GLfloat)attribState.mDivisor;
+ break;
+ default: return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+{
+ EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
+
+ switch (pname)
+ {
+ case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+ *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+ *params = attribState.mSize;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+ *params = attribState.mStride;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+ *params = attribState.mType;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+ *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+ *params = attribState.mBoundBuffer.id();
+ break;
+ case GL_CURRENT_VERTEX_ATTRIB:
+ for (int i = 0; i < 4; ++i)
+ {
+ float currentValue = attribState.mCurrentValue[i];
+ params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f));
+ }
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE:
+ *params = (GLint)attribState.mDivisor;
+ break;
+ default: return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
+{
+ EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ *pointer = const_cast<GLvoid*>(context->getVertexAttribPointer(index));
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glHint(GLenum target, GLenum mode)
+{
+ EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode);
+
+ try
+ {
+ switch (mode)
+ {
+ case GL_FASTEST:
+ case GL_NICEST:
+ case GL_DONT_CARE:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+ switch (target)
+ {
+ case GL_GENERATE_MIPMAP_HINT:
+ if (context) context->setGenerateMipmapHint(mode);
+ break;
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
+ if (context) context->setFragmentShaderDerivativeHint(mode);
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLboolean __stdcall glIsBuffer(GLuint buffer)
+{
+ EVENT("(GLuint buffer = %d)", buffer);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context && buffer)
+ {
+ gl::Buffer *bufferObject = context->getBuffer(buffer);
+
+ if (bufferObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsEnabled(GLenum cap)
+{
+ EVENT("(GLenum cap = 0x%X)", cap);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (cap)
+ {
+ case GL_CULL_FACE: return context->isCullFaceEnabled();
+ case GL_POLYGON_OFFSET_FILL: return context->isPolygonOffsetFillEnabled();
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: return context->isSampleAlphaToCoverageEnabled();
+ case GL_SAMPLE_COVERAGE: return context->isSampleCoverageEnabled();
+ case GL_SCISSOR_TEST: return context->isScissorTestEnabled();
+ case GL_STENCIL_TEST: return context->isStencilTestEnabled();
+ case GL_DEPTH_TEST: return context->isDepthTestEnabled();
+ case GL_BLEND: return context->isBlendEnabled();
+ case GL_DITHER: return context->isDitherEnabled();
+ default:
+ return gl::error(GL_INVALID_ENUM, false);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ return false;
+}
+
+GLboolean __stdcall glIsFenceNV(GLuint fence)
+{
+ EVENT("(GLuint fence = %d)", fence);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Fence *fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return GL_FALSE;
+ }
+
+ return fenceObject->isFence();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsFramebuffer(GLuint framebuffer)
+{
+ EVENT("(GLuint framebuffer = %d)", framebuffer);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context && framebuffer)
+ {
+ gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer);
+
+ if (framebufferObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context && program)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (programObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsQueryEXT(GLuint id)
+{
+ EVENT("(GLuint id = %d)", id);
+
+ try
+ {
+ if (id == 0)
+ {
+ return GL_FALSE;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Query *queryObject = context->getQuery(id, false, GL_NONE);
+
+ if (queryObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer)
+{
+ EVENT("(GLuint renderbuffer = %d)", renderbuffer);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context && renderbuffer)
+ {
+ gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer);
+
+ if (renderbufferObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsShader(GLuint shader)
+{
+ EVENT("(GLuint shader = %d)", shader);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context && shader)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (shaderObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsTexture(GLuint texture)
+{
+ EVENT("(GLuint texture = %d)", texture);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context && texture)
+ {
+ gl::Texture *textureObject = context->getTexture(texture);
+
+ if (textureObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+void __stdcall glLineWidth(GLfloat width)
+{
+ EVENT("(GLfloat width = %f)", width);
+
+ try
+ {
+ if (width <= 0.0f)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setLineWidth(width);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glLinkProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ context->linkProgram(program);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glPixelStorei(GLenum pname, GLint param)
+{
+ EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (pname)
+ {
+ case GL_UNPACK_ALIGNMENT:
+ if (param != 1 && param != 2 && param != 4 && param != 8)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ context->setUnpackAlignment(param);
+ break;
+
+ case GL_PACK_ALIGNMENT:
+ if (param != 1 && param != 2 && param != 4 && param != 8)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ context->setPackAlignment(param);
+ break;
+
+ case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
+ context->setPackReverseRowOrder(param != 0);
+ break;
+
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glPolygonOffset(GLfloat factor, GLfloat units)
+{
+ EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setPolygonOffsetParams(factor, units);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLsizei bufSize,
+ GLvoid *data)
+{
+ EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, "
+ "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = 0x%0.8p)",
+ x, y, width, height, format, type, bufSize, data);
+
+ try
+ {
+ if (width < 0 || height < 0 || bufSize < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ GLenum currentFormat, currentType;
+
+ // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
+ // and attempting to read back if that's the case is an error. The error will be registered
+ // by getCurrentReadFormat.
+ if (!context->getCurrentReadFormatType(&currentFormat, &currentType))
+ return;
+
+ if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ context->readPixels(x, y, width, height, format, type, &bufSize, data);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid* pixels)
+{
+ EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, "
+ "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = 0x%0.8p)",
+ x, y, width, height, format, type, pixels);
+
+ try
+ {
+ if (width < 0 || height < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ GLenum currentFormat, currentType;
+
+ // Failure in getCurrentReadFormatType indicates that no color attachment is currently bound,
+ // and attempting to read back if that's the case is an error. The error will be registered
+ // by getCurrentReadFormat.
+ if (!context->getCurrentReadFormatType(&currentFormat, &currentType))
+ return;
+
+ if (!(currentFormat == format && currentType == type) && !validReadFormatType(format, type))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ context->readPixels(x, y, width, height, format, type, NULL, pixels);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glReleaseShaderCompiler(void)
+{
+ EVENT("()");
+
+ try
+ {
+ gl::Shader::releaseCompiler();
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
+ target, samples, internalformat, width, height);
+
+ try
+ {
+ switch (target)
+ {
+ case GL_RENDERBUFFER:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (!gl::IsColorRenderable(internalformat) && !gl::IsDepthRenderable(internalformat) && !gl::IsStencilRenderable(internalformat))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (width < 0 || height < 0 || samples < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (width > context->getMaximumRenderbufferDimension() ||
+ height > context->getMaximumRenderbufferDimension() ||
+ samples > context->getMaxSupportedSamples())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ GLuint handle = context->getRenderbufferHandle();
+ if (handle == 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ switch (internalformat)
+ {
+ case GL_DEPTH_COMPONENT16:
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES:
+ context->setRenderbufferStorage(width, height, internalformat, samples);
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height);
+}
+
+void __stdcall glSampleCoverage(GLclampf value, GLboolean invert)
+{
+ EVENT("(GLclampf value = %f, GLboolean invert = %d)", value, invert);
+
+ try
+ {
+ gl::Context* context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glSetFenceNV(GLuint fence, GLenum condition)
+{
+ EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition);
+
+ try
+ {
+ if (condition != GL_ALL_COMPLETED_NV)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Fence *fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ fenceObject->setFence(condition);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
+
+ try
+ {
+ if (width < 0 || height < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context* context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setScissorParams(x, y, width, height);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
+{
+ EVENT("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, "
+ "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)",
+ n, shaders, binaryformat, binary, length);
+
+ try
+ {
+ // No binary shader formats are supported.
+ return gl::error(GL_INVALID_ENUM);
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
+{
+ EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)",
+ shader, count, string, length);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ if (context->getProgram(shader))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ shaderObject->setSource(count, string, length);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+ glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);
+}
+
+void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+ EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask);
+
+ try
+ {
+ switch (face)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ 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:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilParams(func, ref, mask);
+ }
+
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilBackParams(func, ref, mask);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glStencilMask(GLuint mask)
+{
+ glStencilMaskSeparate(GL_FRONT_AND_BACK, mask);
+}
+
+void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask)
+{
+ EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask);
+
+ try
+ {
+ switch (face)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilWritemask(mask);
+ }
+
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilBackWritemask(mask);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+{
+ glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass);
+}
+
+void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+ EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)",
+ face, fail, zfail, zpass);
+
+ try
+ {
+ switch (face)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (fail)
+ {
+ 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:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (zfail)
+ {
+ 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:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (zpass)
+ {
+ 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:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilOperations(fail, zfail, zpass);
+ }
+
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilBackOperations(fail, zfail, zpass);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLboolean __stdcall glTestFenceNV(GLuint fence)
+{
+ EVENT("(GLuint fence = %d)", fence);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Fence *fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION, GL_TRUE);
+ }
+
+ return fenceObject->testFence();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ return GL_TRUE;
+}
+
+void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, "
+ "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)",
+ target, level, internalformat, width, height, border, format, type, pixels);
+
+ try
+ {
+ if (!validImageSize(level, width, height))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (internalformat != GLint(format))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ // validate <type> 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:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ // validate <format> + <type> combinations
+ // - invalid <format> -> sets INVALID_ENUM
+ // - invalid <format>+<type> 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:
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ 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:
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ 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:
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_BGRA_EXT:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ break;
+ default:
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ 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:
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_DEPTH_STENCIL_OES:
+ switch (type)
+ {
+ case GL_UNSIGNED_INT_24_8_OES:
+ break;
+ default:
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (border != 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ if (width > (context->getMaximumTextureDimension() >> level) ||
+ height > (context->getMaximumTextureDimension() >> level))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ 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 (width != height)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (width > (context->getMaximumCubeTextureDimension() >> level) ||
+ height > (context->getMaximumCubeTextureDimension() >> level))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (format) {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ if (context->supportsDXT1Textures())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ if (context->supportsDXT3Textures())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ if (context->supportsDXT5Textures())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_STENCIL_OES:
+ if (!context->supportsDepthTextures())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ if (target != GL_TEXTURE_2D)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ // OES_depth_texture supports loading depth data and multiple levels,
+ // but ANGLE_depth_texture does not
+ if (pixels != NULL || level != 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (type == GL_FLOAT)
+ {
+ if (!context->supportsFloat32Textures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ else if (type == GL_HALF_FLOAT_OES)
+ {
+ if (!context->supportsFloat16Textures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if (!texture)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (texture->isImmutable())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ texture->setImage(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ }
+ else
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if (!texture)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (texture->isImmutable())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ texture->setImagePosX(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ texture->setImageNegX(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ texture->setImagePosY(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ texture->setImageNegY(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ texture->setImagePosZ(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ texture->setImageNegZ(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Texture *texture;
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (pname)
+ {
+ case GL_TEXTURE_WRAP_S:
+ if (!texture->setWrapS((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_WRAP_T:
+ if (!texture->setWrapT((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_MIN_FILTER:
+ if (!texture->setMinFilter((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_MAG_FILTER:
+ if (!texture->setMagFilter((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_USAGE_ANGLE:
+ if (!texture->setUsage((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+ if (!context->supportsTextureFilterAnisotropy())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy()))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
+{
+ glTexParameterf(target, pname, (GLfloat)*params);
+}
+
+void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Texture *texture;
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ switch (pname)
+ {
+ case GL_TEXTURE_WRAP_S:
+ if (!texture->setWrapS((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_WRAP_T:
+ if (!texture->setWrapT((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_MIN_FILTER:
+ if (!texture->setMinFilter((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_MAG_FILTER:
+ if (!texture->setMagFilter((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_USAGE_ANGLE:
+ if (!texture->setUsage((GLenum)param))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+ if (!context->supportsTextureFilterAnisotropy())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ if (!texture->setMaxAnisotropy((float)param, context->getTextureMaxAnisotropy()))
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
+{
+ glTexParameteri(target, pname, *params);
+}
+
+void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
+ target, levels, internalformat, width, height);
+
+ try
+ {
+ if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (width < 1 || height < 1 || levels < 1)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (target == GL_TEXTURE_CUBE_MAP && width != height)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ GLenum format = gl::ExtractFormat(internalformat);
+ GLenum type = gl::ExtractType(internalformat);
+
+ if (format == GL_NONE || type == GL_NONE)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ if (width > context->getMaximumTextureDimension() ||
+ height > context->getMaximumTextureDimension())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ if (width > context->getMaximumCubeTextureDimension() ||
+ height > context->getMaximumCubeTextureDimension())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (levels != 1 && !context->supportsNonPower2Texture())
+ {
+ if (!gl::isPow2(width) || !gl::isPow2(height))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+
+ switch (internalformat)
+ {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ if (!context->supportsDXT1Textures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ if (!context->supportsDXT3Textures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ if (!context->supportsDXT5Textures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_RGBA32F_EXT:
+ case GL_RGB32F_EXT:
+ case GL_ALPHA32F_EXT:
+ case GL_LUMINANCE32F_EXT:
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ if (!context->supportsFloat32Textures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_RGBA16F_EXT:
+ case GL_RGB16F_EXT:
+ case GL_ALPHA16F_EXT:
+ case GL_LUMINANCE16F_EXT:
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ if (!context->supportsFloat16Textures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_DEPTH_COMPONENT16:
+ case GL_DEPTH_COMPONENT32_OES:
+ case GL_DEPTH24_STENCIL8_OES:
+ if (!context->supportsDepthTextures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ if (target != GL_TEXTURE_2D)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ // ANGLE_depth_texture only supports 1-level textures
+ if (levels != 1)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if (!texture || texture->id() == 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (texture->isImmutable())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ texture->storage(levels, internalformat, width, height);
+ }
+ else if (target == GL_TEXTURE_CUBE_MAP)
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if (!texture || texture->id() == 0)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (texture->isImmutable())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ texture->storage(levels, internalformat, width);
+ }
+ else UNREACHABLE();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid* pixels)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, "
+ "const GLvoid* pixels = 0x%0.8p)",
+ target, level, xoffset, yoffset, width, height, format, type, pixels);
+
+ try
+ {
+ if (!gl::IsInternalTextureTarget(target))
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (!checkTextureFormatType(format, type))
+ {
+ return; // error is set by helper function
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (format == GL_FLOAT)
+ {
+ if (!context->supportsFloat32Textures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ else if (format == GL_HALF_FLOAT_OES)
+ {
+ if (!context->supportsFloat16Textures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ }
+ else if (gl::IsDepthTexture(format))
+ {
+ if (!context->supportsDepthTextures())
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+ if (target != GL_TEXTURE_2D)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ // OES_depth_texture supports loading depth data, but ANGLE_depth_texture does not
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (width == 0 || height == 0 || pixels == NULL)
+ {
+ return;
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+ if (validateSubImageParams2D(false, width, height, xoffset, yoffset, level, format, type, texture))
+ {
+ texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
+ }
+ }
+ else if (gl::IsCubemapTextureTarget(target))
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+ if (validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, format, type, texture))
+ {
+ texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
+ }
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform1f(GLint location, GLfloat x)
+{
+ glUniform1fv(location, 1, &x);
+}
+
+void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniform1fv(location, count, v))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform1i(GLint location, GLint x)
+{
+ glUniform1iv(location, 1, &x);
+}
+
+void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniform1iv(location, count, v))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y)
+{
+ GLfloat xy[2] = {x, y};
+
+ glUniform2fv(location, 1, (GLfloat*)&xy);
+}
+
+void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniform2fv(location, count, v))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform2i(GLint location, GLint x, GLint y)
+{
+ GLint xy[4] = {x, y};
+
+ glUniform2iv(location, 1, (GLint*)&xy);
+}
+
+void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniform2iv(location, count, v))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+ GLfloat xyz[3] = {x, y, z};
+
+ glUniform3fv(location, 1, (GLfloat*)&xyz);
+}
+
+void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniform3fv(location, count, v))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z)
+{
+ GLint xyz[3] = {x, y, z};
+
+ glUniform3iv(location, 1, (GLint*)&xyz);
+}
+
+void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniform3iv(location, count, v))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GLfloat xyzw[4] = {x, y, z, w};
+
+ glUniform4fv(location, 1, (GLfloat*)&xyzw);
+}
+
+void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniform4fv(location, count, v))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+ GLint xyzw[4] = {x, y, z, w};
+
+ glUniform4iv(location, 1, (GLint*)&xyzw);
+}
+
+void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniform4iv(location, count, v))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
+ location, count, transpose, value);
+
+ try
+ {
+ if (count < 0 || transpose != GL_FALSE)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniformMatrix2fv(location, count, value))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
+ location, count, transpose, value);
+
+ try
+ {
+ if (count < 0 || transpose != GL_FALSE)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniformMatrix3fv(location, count, value))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
+ location, count, transpose, value);
+
+ try
+ {
+ if (count < 0 || transpose != GL_FALSE)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::ProgramBinary *programBinary = context->getCurrentProgramBinary();
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->setUniformMatrix4fv(location, count, value))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUseProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject && program != 0)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (program != 0 && !programObject->isLinked())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ context->useProgram(program);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glValidateProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+ }
+
+ programObject->validate();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib1f(GLuint index, GLfloat x)
+{
+ EVENT("(GLuint index = %d, GLfloat x = %f)", index, x);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { x, 0, 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values)
+{
+ EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { values[0], 0, 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y)
+{
+ EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { x, y, 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values)
+{
+ EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { values[0], values[1], 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)
+{
+ EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { x, y, z, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values)
+{
+ EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { values[0], values[1], values[2], 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { x, y, z, w };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values)
+{
+ EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setVertexAttrib(index, values);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttribDivisorANGLE(GLuint index, GLuint divisor)
+{
+ EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setVertexAttribDivisor(index, divisor);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+{
+ EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, "
+ "GLboolean normalized = %d, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)",
+ index, size, type, normalized, stride, ptr);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (size < 1 || size > 4)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ switch (type)
+ {
+ case GL_BYTE:
+ case GL_UNSIGNED_BYTE:
+ case GL_SHORT:
+ case GL_UNSIGNED_SHORT:
+ case GL_FIXED:
+ case GL_FLOAT:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if (stride < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized == GL_TRUE), stride, ptr);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
+
+ try
+ {
+ if (width < 0 || height < 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ context->setViewportParams(x, y, width, height);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
+ "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
+ "GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
+ srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+
+ try
+ {
+ switch (filter)
+ {
+ case GL_NEAREST:
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)
+ {
+ ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation");
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
+ {
+ ERR("Blits with the same source and destination framebuffer are not supported by this implementation.");
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
+ "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, "
+ "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)",
+ target, level, internalformat, width, height, depth, border, format, type, pixels);
+
+ try
+ {
+ UNIMPLEMENTED(); // FIXME
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length,
+ GLenum *binaryFormat, void *binary)
+{
+ EVENT("(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)",
+ program, bufSize, length, binaryFormat, binary);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject || !programObject->isLinked())
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+
+ if (!programBinary)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (!programBinary->save(binary, bufSize, length))
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ *binaryFormat = GL_PROGRAM_BINARY_ANGLE;
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat,
+ const void *binary, GLint length)
+{
+ EVENT("(GLenum program = 0x%X, binaryFormat = 0x%x, binary = 0x%0.8p, length = %d)",
+ program, binaryFormat, binary, length);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (binaryFormat != GL_PROGRAM_BINARY_ANGLE)
+ {
+ return gl::error(GL_INVALID_ENUM);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ context->setProgramBinary(program, binary, length);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs)
+{
+ EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ if (n < 0 || (unsigned int)n > context->getMaximumRenderTargets())
+ {
+ return gl::error(GL_INVALID_VALUE);
+ }
+
+ if (context->getDrawFramebufferHandle() == 0)
+ {
+ if (n != 1)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ if (bufs[0] != GL_NONE && bufs[0] != GL_BACK)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ else
+ {
+ for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
+ {
+ const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment;
+ if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+
+ gl::Framebuffer *framebuffer = context->getDrawFramebuffer();
+
+ for (int colorAttachment = 0; colorAttachment < n; colorAttachment++)
+ {
+ framebuffer->setDrawBufferState(colorAttachment, bufs[colorAttachment]);
+ }
+
+ for (int colorAttachment = n; colorAttachment < (int)context->getMaximumRenderTargets(); colorAttachment++)
+ {
+ framebuffer->setDrawBufferState(colorAttachment, GL_NONE);
+ }
+ }
+ }
+ catch (std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+__eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname)
+{
+ struct Extension
+ {
+ const char *name;
+ __eglMustCastToProperFunctionPointerType address;
+ };
+
+ static const Extension glExtensions[] =
+ {
+ {"glTexImage3DOES", (__eglMustCastToProperFunctionPointerType)glTexImage3DOES},
+ {"glBlitFramebufferANGLE", (__eglMustCastToProperFunctionPointerType)glBlitFramebufferANGLE},
+ {"glRenderbufferStorageMultisampleANGLE", (__eglMustCastToProperFunctionPointerType)glRenderbufferStorageMultisampleANGLE},
+ {"glDeleteFencesNV", (__eglMustCastToProperFunctionPointerType)glDeleteFencesNV},
+ {"glGenFencesNV", (__eglMustCastToProperFunctionPointerType)glGenFencesNV},
+ {"glIsFenceNV", (__eglMustCastToProperFunctionPointerType)glIsFenceNV},
+ {"glTestFenceNV", (__eglMustCastToProperFunctionPointerType)glTestFenceNV},
+ {"glGetFenceivNV", (__eglMustCastToProperFunctionPointerType)glGetFenceivNV},
+ {"glFinishFenceNV", (__eglMustCastToProperFunctionPointerType)glFinishFenceNV},
+ {"glSetFenceNV", (__eglMustCastToProperFunctionPointerType)glSetFenceNV},
+ {"glGetTranslatedShaderSourceANGLE", (__eglMustCastToProperFunctionPointerType)glGetTranslatedShaderSourceANGLE},
+ {"glTexStorage2DEXT", (__eglMustCastToProperFunctionPointerType)glTexStorage2DEXT},
+ {"glGetGraphicsResetStatusEXT", (__eglMustCastToProperFunctionPointerType)glGetGraphicsResetStatusEXT},
+ {"glReadnPixelsEXT", (__eglMustCastToProperFunctionPointerType)glReadnPixelsEXT},
+ {"glGetnUniformfvEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformfvEXT},
+ {"glGetnUniformivEXT", (__eglMustCastToProperFunctionPointerType)glGetnUniformivEXT},
+ {"glGenQueriesEXT", (__eglMustCastToProperFunctionPointerType)glGenQueriesEXT},
+ {"glDeleteQueriesEXT", (__eglMustCastToProperFunctionPointerType)glDeleteQueriesEXT},
+ {"glIsQueryEXT", (__eglMustCastToProperFunctionPointerType)glIsQueryEXT},
+ {"glBeginQueryEXT", (__eglMustCastToProperFunctionPointerType)glBeginQueryEXT},
+ {"glEndQueryEXT", (__eglMustCastToProperFunctionPointerType)glEndQueryEXT},
+ {"glGetQueryivEXT", (__eglMustCastToProperFunctionPointerType)glGetQueryivEXT},
+ {"glGetQueryObjectuivEXT", (__eglMustCastToProperFunctionPointerType)glGetQueryObjectuivEXT},
+ {"glDrawBuffersEXT", (__eglMustCastToProperFunctionPointerType)glDrawBuffersEXT},
+ {"glVertexAttribDivisorANGLE", (__eglMustCastToProperFunctionPointerType)glVertexAttribDivisorANGLE},
+ {"glDrawArraysInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawArraysInstancedANGLE},
+ {"glDrawElementsInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawElementsInstancedANGLE},
+ {"glGetProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glGetProgramBinaryOES},
+ {"glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glProgramBinaryOES}, };
+
+ for (unsigned int ext = 0; ext < ArraySize(glExtensions); ext++)
+ {
+ if (strcmp(procname, glExtensions[ext].name) == 0)
+ {
+ return (__eglMustCastToProperFunctionPointerType)glExtensions[ext].address;
+ }
+ }
+
+ return NULL;
+}
+
+// Non-public functions used by EGL
+
+bool __stdcall glBindTexImage(egl::Surface *surface)
+{
+ EVENT("(egl::Surface* surface = 0x%0.8p)",
+ surface);
+
+ try
+ {
+ gl::Context *context = gl::getNonLostContext();
+
+ if (context)
+ {
+ gl::Texture2D *textureObject = context->getTexture2D();
+
+ if (textureObject->isImmutable())
+ {
+ return false;
+ }
+
+ if (textureObject)
+ {
+ textureObject->bindTexImage(surface);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ return true;
+}
+
+}
diff --git a/src/libGLESv2/libGLESv2.def b/src/libGLESv2/libGLESv2.def
new file mode 100644
index 00000000..71398b31
--- /dev/null
+++ b/src/libGLESv2/libGLESv2.def
@@ -0,0 +1,185 @@
+LIBRARY libGLESv2
+EXPORTS
+ glActiveTexture @1
+ glAttachShader @2
+ glBindAttribLocation @3
+ glBindBuffer @4
+ glBindFramebuffer @5
+ glBindRenderbuffer @6
+ glBindTexture @7
+ glBlendColor @8
+ glBlendEquation @9
+ glBlendEquationSeparate @10
+ glBlendFunc @11
+ glBlendFuncSeparate @12
+ glBufferData @13
+ glBufferSubData @14
+ glCheckFramebufferStatus @15
+ glClear @16
+ glClearColor @17
+ glClearDepthf @18
+ glClearStencil @19
+ glColorMask @20
+ glCompileShader @21
+ glCompressedTexImage2D @22
+ glCompressedTexSubImage2D @23
+ glCopyTexImage2D @24
+ glCopyTexSubImage2D @25
+ glCreateProgram @26
+ glCreateShader @27
+ glCullFace @28
+ glDeleteBuffers @29
+ glDeleteFramebuffers @30
+ glDeleteProgram @32
+ glDeleteRenderbuffers @33
+ glDeleteShader @34
+ glDeleteTextures @31
+ glDepthFunc @36
+ glDepthMask @37
+ glDepthRangef @38
+ glDetachShader @35
+ glDisable @39
+ glDisableVertexAttribArray @40
+ glDrawArrays @41
+ glDrawElements @42
+ glEnable @43
+ glEnableVertexAttribArray @44
+ glFinish @45
+ glFlush @46
+ glFramebufferRenderbuffer @47
+ glFramebufferTexture2D @48
+ glFrontFace @49
+ glGenBuffers @50
+ glGenFramebuffers @52
+ glGenRenderbuffers @53
+ glGenTextures @54
+ glGenerateMipmap @51
+ glGetActiveAttrib @55
+ glGetActiveUniform @56
+ glGetAttachedShaders @57
+ glGetAttribLocation @58
+ glGetBooleanv @59
+ glGetBufferParameteriv @60
+ glGetError @61
+ glGetFloatv @62
+ glGetFramebufferAttachmentParameteriv @63
+ glGetIntegerv @64
+ glGetProgramInfoLog @66
+ glGetProgramiv @65
+ glGetRenderbufferParameteriv @67
+ glGetShaderInfoLog @69
+ glGetShaderPrecisionFormat @70
+ glGetShaderSource @71
+ glGetShaderiv @68
+ glGetString @72
+ glGetTexParameterfv @73
+ glGetTexParameteriv @74
+ glGetUniformLocation @77
+ glGetUniformfv @75
+ glGetUniformiv @76
+ glGetVertexAttribPointerv @80
+ glGetVertexAttribfv @78
+ glGetVertexAttribiv @79
+ glHint @81
+ glIsBuffer @82
+ glIsEnabled @83
+ glIsFramebuffer @84
+ glIsProgram @85
+ glIsRenderbuffer @86
+ glIsShader @87
+ glIsTexture @88
+ glLineWidth @89
+ glLinkProgram @90
+ glPixelStorei @91
+ glPolygonOffset @92
+ glReadPixels @93
+ glReleaseShaderCompiler @94
+ glRenderbufferStorage @95
+ glSampleCoverage @96
+ glScissor @97
+ glShaderBinary @98
+ glShaderSource @99
+ glStencilFunc @100
+ glStencilFuncSeparate @101
+ glStencilMask @102
+ glStencilMaskSeparate @103
+ glStencilOp @104
+ glStencilOpSeparate @105
+ glTexImage2D @106
+ glTexParameterf @107
+ glTexParameterfv @108
+ glTexParameteri @109
+ glTexParameteriv @110
+ glTexSubImage2D @111
+ glUniform1f @112
+ glUniform1fv @113
+ glUniform1i @114
+ glUniform1iv @115
+ glUniform2f @116
+ glUniform2fv @117
+ glUniform2i @118
+ glUniform2iv @119
+ glUniform3f @120
+ glUniform3fv @121
+ glUniform3i @122
+ glUniform3iv @123
+ glUniform4f @124
+ glUniform4fv @125
+ glUniform4i @126
+ glUniform4iv @127
+ glUniformMatrix2fv @128
+ glUniformMatrix3fv @129
+ glUniformMatrix4fv @130
+ glUseProgram @131
+ glValidateProgram @132
+ glVertexAttrib1f @133
+ glVertexAttrib1fv @134
+ glVertexAttrib2f @135
+ glVertexAttrib2fv @136
+ glVertexAttrib3f @137
+ glVertexAttrib3fv @138
+ glVertexAttrib4f @139
+ glVertexAttrib4fv @140
+ glVertexAttribPointer @141
+ glViewport @142
+
+ ; Extensions
+ glTexImage3DOES @143
+ glBlitFramebufferANGLE @149
+ glRenderbufferStorageMultisampleANGLE @150
+ glDeleteFencesNV @151
+ glFinishFenceNV @152
+ glGenFencesNV @153
+ glGetFenceivNV @154
+ glIsFenceNV @155
+ glSetFenceNV @156
+ glTestFenceNV @157
+ glGetTranslatedShaderSourceANGLE @159
+ glTexStorage2DEXT @160
+ glGetGraphicsResetStatusEXT @161
+ glReadnPixelsEXT @162
+ glGetnUniformfvEXT @163
+ glGetnUniformivEXT @164
+ glGenQueriesEXT @165
+ glDeleteQueriesEXT @166
+ glIsQueryEXT @167
+ glBeginQueryEXT @168
+ glEndQueryEXT @169
+ glGetQueryivEXT @170
+ glGetQueryObjectuivEXT @171
+ glVertexAttribDivisorANGLE @172
+ glDrawArraysInstancedANGLE @173
+ glDrawElementsInstancedANGLE @174
+ glProgramBinaryOES @175
+ glGetProgramBinaryOES @176
+ glDrawBuffersEXT @179
+
+ ; EGL dependencies
+ glCreateContext @144 NONAME
+ glDestroyContext @145 NONAME
+ glMakeCurrent @146 NONAME
+ glGetCurrentContext @147 NONAME
+ glGetProcAddress @148 NONAME
+ glBindTexImage @158 NONAME
+ glCreateRenderer @177 NONAME
+ glDestroyRenderer @178 NONAME \ No newline at end of file
diff --git a/src/libGLESv2/libGLESv2.rc b/src/libGLESv2/libGLESv2.rc
new file mode 100644
index 00000000..0ad21e44
--- /dev/null
+++ b/src/libGLESv2/libGLESv2.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+#include "../common/version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "#include ""../common/version.h""\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "ANGLE libGLESv2 Dynamic Link Library"
+ VALUE "FileVersion", VERSION_STRING
+ VALUE "InternalName", "libGLESv2"
+ VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc."
+ VALUE "OriginalFilename", "libGLESv2.dll"
+ VALUE "PrivateBuild", VERSION_STRING
+ VALUE "ProductName", "ANGLE libGLESv2 Dynamic Link Library"
+ VALUE "ProductVersion", VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/src/libGLESv2/libGLESv2.vcxproj b/src/libGLESv2/libGLESv2.vcxproj
new file mode 100644
index 00000000..906707c9
--- /dev/null
+++ b/src/libGLESv2/libGLESv2.vcxproj
@@ -0,0 +1,425 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B5871A7A-968C-42E3-A33B-981E6F448E78}</ProjectGuid>
+ <RootNamespace>libGLESv2</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IncludePath)</IncludePath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(LibraryPath)</LibraryPath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IncludePath)</IncludePath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(LibraryPath)</LibraryPath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IncludePath)</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IncludePath)</IncludePath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(LibraryPath)</LibraryPath>
+ <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)/..; $(ProjectDir)/../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
+ <AdditionalOptions>$(ExternalCompilerOptions) %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>%40echo on
+mkdir "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.lib" "$(ProjectDir)..\..\lib\$(Configuration)\"
+%40echo off
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)/..; $(ProjectDir)/../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>ANGLE_DISABLE_TRACE;WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;4718;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
+ <AdditionalOptions>$(ExternalCompilerOptions) %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>%40echo on
+mkdir "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.lib" "$(ProjectDir)..\..\lib\$(Configuration)\"
+%40echo off
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(ProjectDir)/..; $(ProjectDir)/../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;4718;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
+ <AdditionalOptions>$(ExternalCompilerOptions) %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>%40echo on
+mkdir "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.lib" "$(ProjectDir)..\..\lib\$(Configuration)\"
+%40echo off
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>$(ProjectDir)/..; $(ProjectDir)/../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level4</WarningLevel>
+ <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4512;4702;4718;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
+ <AdditionalOptions>$(ExternalCompilerOptions) %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>d3d9.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <ModuleDefinitionFile>libGLESv2.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>%40echo on
+mkdir "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.dll" "$(ProjectDir)..\..\lib\$(Configuration)\"
+copy "$(OutDir)libGLESv2.lib" "$(ProjectDir)..\..\lib\$(Configuration)\"
+%40echo off
+</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\third_party\murmurhash\MurmurHash3.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="Buffer.cpp" />
+ <ClCompile Include="Context.cpp" />
+ <ClCompile Include="..\common\debug.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="Fence.cpp" />
+ <ClCompile Include="Float16ToFloat32.cpp" />
+ <ClCompile Include="Framebuffer.cpp" />
+ <ClCompile Include="HandleAllocator.cpp" />
+ <ClCompile Include="libGLESv2.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="precompiled.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="Program.cpp" />
+ <ClCompile Include="ProgramBinary.cpp" />
+ <ClCompile Include="Query.cpp" />
+ <ClCompile Include="..\common\RefCountObject.cpp" />
+ <ClCompile Include="Renderbuffer.cpp" />
+ <ClCompile Include="renderer\Blit.cpp" />
+ <ClCompile Include="renderer\Fence11.cpp" />
+ <ClCompile Include="renderer\Fence9.cpp" />
+ <ClCompile Include="renderer\BufferStorage.cpp" />
+ <ClCompile Include="renderer\BufferStorage11.cpp" />
+ <ClCompile Include="renderer\BufferStorage9.cpp" />
+ <ClCompile Include="renderer\Image.cpp" />
+ <ClCompile Include="renderer\Image9.cpp" />
+ <ClCompile Include="renderer\IndexBuffer.cpp" />
+ <ClCompile Include="renderer\IndexBuffer11.cpp" />
+ <ClCompile Include="renderer\IndexBuffer9.cpp" />
+ <ClCompile Include="renderer\IndexDataManager.cpp" />
+ <ClCompile Include="renderer\ImageSSE2.cpp" />
+ <ClCompile Include="renderer\Image11.cpp" />
+ <ClCompile Include="renderer\IndexRangeCache.cpp" />
+ <ClCompile Include="renderer\InputLayoutCache.cpp" />
+ <ClCompile Include="renderer\Query11.cpp" />
+ <ClCompile Include="renderer\Query9.cpp" />
+ <ClCompile Include="renderer\Renderer.cpp" />
+ <ClCompile Include="renderer\Renderer11.cpp" />
+ <ClCompile Include="renderer\renderer11_utils.cpp" />
+ <ClCompile Include="renderer\Renderer9.cpp" />
+ <ClCompile Include="renderer\renderer9_utils.cpp" />
+ <ClCompile Include="renderer\RenderTarget11.cpp" />
+ <ClCompile Include="renderer\RenderTarget9.cpp" />
+ <ClCompile Include="renderer\RenderStateCache.cpp" />
+ <ClCompile Include="renderer\ShaderExecutable11.cpp" />
+ <ClCompile Include="renderer\ShaderExecutable9.cpp" />
+ <ClCompile Include="renderer\SwapChain11.cpp" />
+ <ClCompile Include="renderer\SwapChain9.cpp" />
+ <ClCompile Include="renderer\TextureStorage.cpp" />
+ <ClCompile Include="renderer\TextureStorage11.cpp" />
+ <ClCompile Include="renderer\TextureStorage9.cpp" />
+ <ClCompile Include="renderer\VertexBuffer.cpp" />
+ <ClCompile Include="renderer\VertexBuffer11.cpp" />
+ <ClCompile Include="renderer\VertexBuffer9.cpp" />
+ <ClCompile Include="renderer\VertexDataManager.cpp" />
+ <ClCompile Include="renderer\VertexDeclarationCache.cpp" />
+ <ClCompile Include="ResourceManager.cpp" />
+ <ClCompile Include="Shader.cpp" />
+ <ClCompile Include="Texture.cpp" />
+ <ClCompile Include="Uniform.cpp" />
+ <ClCompile Include="utilities.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\common\debug.h" />
+ <ClInclude Include="..\common\system.h" />
+ <ClInclude Include="..\third_party\murmurhash\MurmurHash3.h" />
+ <ClInclude Include="angletypes.h" />
+ <ClInclude Include="BinaryStream.h" />
+ <ClInclude Include="Buffer.h" />
+ <ClInclude Include="constants.h" />
+ <ClInclude Include="Context.h" />
+ <ClInclude Include="Fence.h" />
+ <ClInclude Include="Framebuffer.h" />
+ <ClInclude Include="..\..\include\GLES2\gl2.h" />
+ <ClInclude Include="..\..\include\GLES2\gl2ext.h" />
+ <ClInclude Include="..\..\include\GLES2\gl2platform.h" />
+ <ClInclude Include="HandleAllocator.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="mathutil.h" />
+ <ClInclude Include="precompiled.h" />
+ <ClInclude Include="Program.h" />
+ <ClInclude Include="ProgramBinary.h" />
+ <ClInclude Include="Query.h" />
+ <ClInclude Include="..\common\RefCountObject.h" />
+ <ClInclude Include="Renderbuffer.h" />
+ <ClInclude Include="renderer\Blit.h" />
+ <ClInclude Include="renderer\Fence11.h" />
+ <ClInclude Include="renderer\Fence9.h" />
+ <ClInclude Include="renderer\FenceImpl.h" />
+ <ClInclude Include="renderer\BufferStorage.h" />
+ <ClInclude Include="renderer\BufferStorage11.h" />
+ <ClInclude Include="renderer\BufferStorage9.h" />
+ <ClInclude Include="renderer\generatemip.h" />
+ <ClInclude Include="renderer\Image.h" />
+ <ClInclude Include="renderer\Image11.h" />
+ <ClInclude Include="renderer\Image9.h" />
+ <ClInclude Include="renderer\IndexBuffer.h" />
+ <ClInclude Include="renderer\IndexBuffer11.h" />
+ <ClInclude Include="renderer\IndexBuffer9.h" />
+ <ClInclude Include="renderer\IndexDataManager.h" />
+ <ClInclude Include="renderer\IndexRangeCache.h" />
+ <ClInclude Include="renderer\InputLayoutCache.h" />
+ <ClInclude Include="renderer\Query11.h" />
+ <ClInclude Include="renderer\QueryImpl.h" />
+ <ClInclude Include="renderer\Query9.h" />
+ <ClInclude Include="renderer\Renderer.h" />
+ <ClInclude Include="renderer\Renderer11.h" />
+ <ClInclude Include="renderer\renderer11_utils.h" />
+ <ClInclude Include="renderer\Renderer9.h" />
+ <ClInclude Include="renderer\renderer9_utils.h" />
+ <ClInclude Include="renderer\RenderTarget.h" />
+ <ClInclude Include="renderer\RenderTarget11.h" />
+ <ClInclude Include="renderer\RenderTarget9.h" />
+ <ClInclude Include="renderer\RenderStateCache.h" />
+ <ClInclude Include="renderer\ShaderCache.h" />
+ <ClInclude Include="renderer\ShaderExecutable.h" />
+ <ClInclude Include="renderer\ShaderExecutable11.h" />
+ <ClInclude Include="renderer\ShaderExecutable9.h" />
+ <ClInclude Include="renderer\shaders\compiled\clear11vs.h" />
+ <ClInclude Include="renderer\shaders\compiled\clearmultiple11ps.h" />
+ <ClInclude Include="renderer\shaders\compiled\clearsingle11ps.h" />
+ <ClInclude Include="renderer\shaders\compiled\componentmaskps.h" />
+ <ClInclude Include="renderer\shaders\compiled\flipyvs.h" />
+ <ClInclude Include="renderer\shaders\compiled\luminanceps.h" />
+ <ClInclude Include="renderer\shaders\compiled\passthrough11vs.h" />
+ <ClInclude Include="renderer\shaders\compiled\passthroughlum11ps.h" />
+ <ClInclude Include="renderer\shaders\compiled\passthroughlumalpha11ps.h" />
+ <ClInclude Include="renderer\shaders\compiled\passthroughps.h" />
+ <ClInclude Include="renderer\shaders\compiled\passthroughrgb11ps.h" />
+ <ClInclude Include="renderer\shaders\compiled\passthroughrgba11ps.h" />
+ <ClInclude Include="renderer\shaders\compiled\standardvs.h" />
+ <ClInclude Include="renderer\SwapChain.h" />
+ <ClInclude Include="renderer\SwapChain11.h" />
+ <ClInclude Include="renderer\SwapChain9.h" />
+ <ClInclude Include="renderer\TextureStorage.h" />
+ <ClInclude Include="renderer\TextureStorage11.h" />
+ <ClInclude Include="renderer\TextureStorage9.h" />
+ <ClInclude Include="renderer\VertexBuffer.h" />
+ <ClInclude Include="renderer\VertexBuffer11.h" />
+ <ClInclude Include="renderer\VertexBuffer9.h" />
+ <ClInclude Include="renderer\vertexconversion.h" />
+ <ClInclude Include="renderer\VertexDataManager.h" />
+ <ClInclude Include="renderer\VertexDeclarationCache.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="ResourceManager.h" />
+ <ClInclude Include="Shader.h" />
+ <ClInclude Include="Texture.h" />
+ <ClInclude Include="Uniform.h" />
+ <ClInclude Include="utilities.h" />
+ <ClInclude Include="..\common\version.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="libGLESv2.def" />
+ <None Include="renderer\shaders\Blit.ps" />
+ <None Include="renderer\shaders\Blit.vs" />
+ <None Include="renderer\shaders\Clear11.hlsl" />
+ <None Include="renderer\shaders\generate_shaders.bat" />
+ <None Include="renderer\shaders\Passthrough11.hlsl" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="libGLESv2.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\compiler\preprocessor\preprocessor.vcxproj">
+ <Project>{fbe32df3-0fb0-4f2f-a424-2c21bd7bc325}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\compiler\translator_common.vcxproj">
+ <Project>{5b3a6db8-1e7e-40d7-92b9-da8aae619fad}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\compiler\translator_hlsl.vcxproj">
+ <Project>{5620f0e4-6c43-49bc-a178-b804e1a0c3a7}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <Private>true</Private>
+ <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/libGLESv2/libGLESv2.vcxproj.filters b/src/libGLESv2/libGLESv2.vcxproj.filters
new file mode 100644
index 00000000..187a46a9
--- /dev/null
+++ b/src/libGLESv2/libGLESv2.vcxproj.filters
@@ -0,0 +1,515 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Third Party">
+ <UniqueIdentifier>{dc1dac40-3563-41be-9e2d-c2588d8670fb}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Third Party\MurmurHash">
+ <UniqueIdentifier>{b0005d2f-9b4a-4659-a270-138811174f73}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\Renderer">
+ <UniqueIdentifier>{562e469d-1abb-44bc-b7fa-55eefbf75acc}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Shaders">
+ <UniqueIdentifier>{6dc0306f-6396-4e80-9ef9-09b58aa53c4d}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Shaders\Compiled">
+ <UniqueIdentifier>{6332705b-1999-4292-a38b-dd47329734aa}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Renderer">
+ <UniqueIdentifier>{93a76964-77a3-4b20-a6f5-e14e762d4e14}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\Renderer9">
+ <UniqueIdentifier>{3877f35e-845c-4e95-b9a5-c7d8b9f307c5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\Renderer11">
+ <UniqueIdentifier>{2d70fd60-6dea-489f-ac09-16890d325669}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Renderer9">
+ <UniqueIdentifier>{60e14f04-2cf2-4a07-b3ef-7c68a82ba2d9}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Renderer11">
+ <UniqueIdentifier>{72db61d3-e081-4b58-bc63-a04a8a70585f}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Buffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Context.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\debug.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Fence.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Float16ToFloat32.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Framebuffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="HandleAllocator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="libGLESv2.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Program.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ProgramBinary.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Query.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\RefCountObject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Renderbuffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ResourceManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Shader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Texture.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utilities.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Image.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\TextureStorage.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Renderer.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="..\third_party\murmurhash\MurmurHash3.cpp">
+ <Filter>Third Party\MurmurHash</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\IndexDataManager.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\VertexDataManager.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Image.cpp">
+ <Filter>Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\ImageSSE2.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\VertexBuffer.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\IndexBuffer.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="Uniform.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\BufferStorage.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\BufferStorage11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Fence11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Image11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\IndexBuffer11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Query11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Renderer11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\renderer11_utils.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\RenderTarget11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\ShaderExecutable11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\SwapChain11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\TextureStorage11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\VertexBuffer11.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\BufferStorage9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Fence9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Image9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\IndexBuffer9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Query9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Renderer9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\renderer9_utils.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\RenderTarget9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\ShaderExecutable9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\SwapChain9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\TextureStorage9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\VertexBuffer9.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\Blit.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\InputLayoutCache.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\RenderStateCache.cpp">
+ <Filter>Source Files\Renderer11</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\VertexDeclarationCache.cpp">
+ <Filter>Source Files\Renderer9</Filter>
+ </ClCompile>
+ <ClCompile Include="precompiled.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="renderer\IndexRangeCache.cpp">
+ <Filter>Source Files\Renderer</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="BinaryStream.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Buffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Context.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Fence.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Framebuffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\GLES2\gl2.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\GLES2\gl2ext.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\GLES2\gl2platform.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="HandleAllocator.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="mathutil.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Program.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ProgramBinary.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Query.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\RefCountObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Renderbuffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ResourceManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Shader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Texture.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="utilities.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="angletypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\third_party\murmurhash\MurmurHash3.h">
+ <Filter>Third Party\MurmurHash</Filter>
+ </ClInclude>
+ <ClInclude Include="Uniform.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\passthrough11vs.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\passthroughps.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\standardvs.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\componentmaskps.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\flipyvs.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\luminanceps.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\passthroughrgba11ps.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\passthroughrgb11ps.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\passthroughlum11ps.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\passthroughlumalpha11ps.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\clear11vs.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\clearmultiple11ps.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\shaders\compiled\clearsingle11ps.h">
+ <Filter>Shaders\Compiled</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\system.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\debug.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\BufferStorage.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\FenceImpl.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\generatemip.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Image.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\IndexBuffer.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\IndexDataManager.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\QueryImpl.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Renderer.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\RenderTarget.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\ShaderExecutable.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\SwapChain.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\TextureStorage.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\VertexBuffer.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\vertexconversion.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\VertexDataManager.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\BufferStorage11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\IndexBuffer11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Query11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Renderer11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\RenderTarget11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\ShaderExecutable11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\SwapChain11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\TextureStorage11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\VertexBuffer11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\BufferStorage9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Fence9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Image9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\IndexBuffer9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Query9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Renderer9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\renderer9_utils.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\RenderTarget9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\ShaderExecutable9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\SwapChain9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\TextureStorage9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\VertexBuffer9.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Fence11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Image11.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\renderer11_utils.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Fence9.h">
+ <Filter>Header Files\Renderer\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Query11.h">
+ <Filter>Header Files\Renderer\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\Blit.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\ShaderCache.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\InputLayoutCache.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\RenderStateCache.h">
+ <Filter>Header Files\Renderer11</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\VertexDeclarationCache.h">
+ <Filter>Header Files\Renderer9</Filter>
+ </ClInclude>
+ <ClInclude Include="constants.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="precompiled.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="renderer\IndexRangeCache.h">
+ <Filter>Header Files\Renderer</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="renderer\shaders\Blit.ps">
+ <Filter>Shaders</Filter>
+ </None>
+ <None Include="renderer\shaders\Blit.vs">
+ <Filter>Shaders</Filter>
+ </None>
+ <None Include="renderer\shaders\generate_shaders.bat">
+ <Filter>Shaders</Filter>
+ </None>
+ <None Include="renderer\shaders\Passthrough11.hlsl">
+ <Filter>Shaders</Filter>
+ </None>
+ <None Include="renderer\shaders\Clear11.hlsl">
+ <Filter>Shaders</Filter>
+ </None>
+ <None Include="libGLESv2.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="libGLESv2.rc" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/libGLESv2/main.cpp b/src/libGLESv2/main.cpp
new file mode 100644
index 00000000..6d7a2413
--- /dev/null
+++ b/src/libGLESv2/main.cpp
@@ -0,0 +1,155 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// main.cpp: DLL entry point and management of thread-local data.
+
+#include "libGLESv2/main.h"
+
+#include "libGLESv2/Context.h"
+
+static DWORD currentTLS = TLS_OUT_OF_INDEXES;
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
+{
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ currentTLS = TlsAlloc();
+
+ if (currentTLS == TLS_OUT_OF_INDEXES)
+ {
+ return FALSE;
+ }
+ }
+ // Fall throught to initialize index
+ case DLL_THREAD_ATTACH:
+ {
+ gl::Current *current = (gl::Current*)LocalAlloc(LPTR, sizeof(gl::Current));
+
+ if (current)
+ {
+ TlsSetValue(currentTLS, current);
+
+ current->context = NULL;
+ current->display = NULL;
+ }
+ }
+ break;
+ case DLL_THREAD_DETACH:
+ {
+ void *current = TlsGetValue(currentTLS);
+
+ if (current)
+ {
+ LocalFree((HLOCAL)current);
+ }
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+ {
+ void *current = TlsGetValue(currentTLS);
+
+ if (current)
+ {
+ LocalFree((HLOCAL)current);
+ }
+
+ TlsFree(currentTLS);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+namespace gl
+{
+void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->context = context;
+ current->display = display;
+
+ if (context && display && surface)
+ {
+ context->makeCurrent(surface);
+ }
+}
+
+Context *getContext()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->context;
+}
+
+Context *getNonLostContext()
+{
+ Context *context = getContext();
+
+ if (context)
+ {
+ if (context->isContextLost())
+ {
+ gl::error(GL_OUT_OF_MEMORY);
+ return NULL;
+ }
+ else
+ {
+ return context;
+ }
+ }
+ return NULL;
+}
+
+egl::Display *getDisplay()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->display;
+}
+
+// Records an error code
+void error(GLenum errorCode)
+{
+ gl::Context *context = glGetCurrentContext();
+
+ if (context)
+ {
+ switch (errorCode)
+ {
+ case GL_INVALID_ENUM:
+ context->recordInvalidEnum();
+ TRACE("\t! Error generated: invalid enum\n");
+ break;
+ case GL_INVALID_VALUE:
+ context->recordInvalidValue();
+ TRACE("\t! Error generated: invalid value\n");
+ break;
+ case GL_INVALID_OPERATION:
+ context->recordInvalidOperation();
+ TRACE("\t! Error generated: invalid operation\n");
+ break;
+ case GL_OUT_OF_MEMORY:
+ context->recordOutOfMemory();
+ TRACE("\t! Error generated: out of memory\n");
+ break;
+ case GL_INVALID_FRAMEBUFFER_OPERATION:
+ context->recordInvalidFramebufferOperation();
+ TRACE("\t! Error generated: invalid framebuffer operation\n");
+ break;
+ default: UNREACHABLE();
+ }
+ }
+}
+
+}
+
diff --git a/src/libGLESv2/main.h b/src/libGLESv2/main.h
new file mode 100644
index 00000000..196afaea
--- /dev/null
+++ b/src/libGLESv2/main.h
@@ -0,0 +1,68 @@
+//
+// 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.
+//
+
+// main.h: Management of thread-local data.
+
+#ifndef LIBGLESV2_MAIN_H_
+#define LIBGLESV2_MAIN_H_
+
+#include "common/debug.h"
+#include "common/system.h"
+
+namespace egl
+{
+class Display;
+class Surface;
+}
+
+namespace gl
+{
+class Context;
+
+struct Current
+{
+ Context *context;
+ egl::Display *display;
+};
+
+void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface);
+
+Context *getContext();
+Context *getNonLostContext();
+egl::Display *getDisplay();
+
+void error(GLenum errorCode);
+
+template<class T>
+const T &error(GLenum errorCode, const T &returnValue)
+{
+ error(errorCode);
+
+ return returnValue;
+}
+
+}
+
+namespace rx
+{
+class Renderer;
+}
+
+extern "C"
+{
+// Exported functions for use by EGL
+gl::Context *glCreateContext(const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess);
+void glDestroyContext(gl::Context *context);
+void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface);
+gl::Context *glGetCurrentContext();
+rx::Renderer *glCreateRenderer(egl::Display *display, HDC hDc, EGLNativeDisplayType displayId);
+void glDestroyRenderer(rx::Renderer *renderer);
+
+__eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname);
+bool __stdcall glBindTexImage(egl::Surface *surface);
+}
+
+#endif // LIBGLESV2_MAIN_H_
diff --git a/src/libGLESv2/mathutil.h b/src/libGLESv2/mathutil.h
new file mode 100644
index 00000000..bb48b94e
--- /dev/null
+++ b/src/libGLESv2/mathutil.h
@@ -0,0 +1,161 @@
+//
+// 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.
+//
+
+// mathutil.h: Math and bit manipulation functions.
+
+#ifndef LIBGLESV2_MATHUTIL_H_
+#define LIBGLESV2_MATHUTIL_H_
+
+#include <intrin.h>
+
+#include "common/system.h"
+#include "common/debug.h"
+
+namespace gl
+{
+struct Vector4
+{
+ Vector4() {}
+ Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
+
+ float x;
+ float y;
+ float z;
+ float w;
+};
+
+inline bool isPow2(int x)
+{
+ return (x & (x - 1)) == 0 && (x != 0);
+}
+
+inline int log2(int x)
+{
+ int r = 0;
+ while ((x >> r) > 1) r++;
+ return r;
+}
+
+inline unsigned int ceilPow2(unsigned int x)
+{
+ if (x != 0) x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x++;
+
+ return x;
+}
+
+template<typename T, typename MIN, typename MAX>
+inline T clamp(T x, MIN min, MAX max)
+{
+ // Since NaNs fail all comparison tests, a NaN value will default to min
+ return x > min ? (x > max ? max : x) : min;
+}
+
+inline float clamp01(float x)
+{
+ return clamp(x, 0.0f, 1.0f);
+}
+
+template<const int n>
+inline unsigned int unorm(float x)
+{
+ const unsigned int max = 0xFFFFFFFF >> (32 - n);
+
+ if (x > 1)
+ {
+ return max;
+ }
+ else if (x < 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return (unsigned int)(max * x + 0.5f);
+ }
+}
+
+inline bool supportsSSE2()
+{
+ static bool checked = false;
+ static bool supports = false;
+
+ if (checked)
+ {
+ return supports;
+ }
+
+ int info[4];
+ __cpuid(info, 0);
+
+ if (info[0] >= 1)
+ {
+ __cpuid(info, 1);
+
+ supports = (info[3] >> 26) & 1;
+ }
+
+ checked = true;
+
+ return supports;
+}
+
+inline unsigned short float32ToFloat16(float fp32)
+{
+ unsigned int fp32i = (unsigned int&)fp32;
+ unsigned int sign = (fp32i & 0x80000000) >> 16;
+ unsigned int abs = fp32i & 0x7FFFFFFF;
+
+ if(abs > 0x47FFEFFF) // Infinity
+ {
+ return sign | 0x7FFF;
+ }
+ else if(abs < 0x38800000) // Denormal
+ {
+ unsigned int mantissa = (abs & 0x007FFFFF) | 0x00800000;
+ int e = 113 - (abs >> 23);
+
+ if(e < 24)
+ {
+ abs = mantissa >> e;
+ }
+ else
+ {
+ abs = 0;
+ }
+
+ return sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13;
+ }
+ else
+ {
+ return sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13;
+ }
+}
+
+float float16ToFloat32(unsigned short h);
+
+}
+
+namespace rx
+{
+
+struct Range
+{
+ Range() {}
+ Range(int lo, int hi) : start(lo), end(hi) { ASSERT(lo <= hi); }
+
+ int start;
+ int end;
+};
+
+}
+
+#endif // LIBGLESV2_MATHUTIL_H_
diff --git a/src/libGLESv2/precompiled.cpp b/src/libGLESv2/precompiled.cpp
new file mode 100644
index 00000000..2621cd6c
--- /dev/null
+++ b/src/libGLESv2/precompiled.cpp
@@ -0,0 +1,9 @@
+//
+// 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.
+//
+
+// precompiled.cpp: Precompiled header source file for libGLESv2.
+
+#include "precompiled.h"
diff --git a/src/libGLESv2/precompiled.h b/src/libGLESv2/precompiled.h
new file mode 100644
index 00000000..a850d57e
--- /dev/null
+++ b/src/libGLESv2/precompiled.h
@@ -0,0 +1,42 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// precompiled.h: Precompiled header file for libGLESv2.
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#define EGLAPI
+#include <EGL/egl.h>
+
+#include <assert.h>
+#include <cstddef>
+#include <float.h>
+#include <intrin.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <algorithm> // for std::min and std::max
+#include <limits>
+#include <map>
+#include <set>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <d3d9.h>
+#include <D3D11.h>
+#include <dxgi.h>
+#include <D3Dcompiler.h>
+
+#ifdef _MSC_VER
+#include <hash_map>
+#endif
diff --git a/src/libGLESv2/renderer/Blit.cpp b/src/libGLESv2/renderer/Blit.cpp
new file mode 100644
index 00000000..2a3ce39c
--- /dev/null
+++ b/src/libGLESv2/renderer/Blit.cpp
@@ -0,0 +1,595 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// Blit.cpp: Surface copy utility class.
+
+#include "libGLESv2/renderer/Blit.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/renderer/renderer9_utils.h"
+#include "libGLESv2/renderer/TextureStorage9.h"
+#include "libGLESv2/renderer/RenderTarget9.h"
+#include "libGLESv2/renderer/Renderer9.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Renderbuffer.h"
+
+namespace
+{
+#include "libGLESv2/renderer/shaders/compiled/standardvs.h"
+#include "libGLESv2/renderer/shaders/compiled/flipyvs.h"
+#include "libGLESv2/renderer/shaders/compiled/passthroughps.h"
+#include "libGLESv2/renderer/shaders/compiled/luminanceps.h"
+#include "libGLESv2/renderer/shaders/compiled/componentmaskps.h"
+
+const BYTE* const g_shaderCode[] =
+{
+ g_vs20_standardvs,
+ g_vs20_flipyvs,
+ g_ps20_passthroughps,
+ g_ps20_luminanceps,
+ g_ps20_componentmaskps
+};
+
+const size_t g_shaderSize[] =
+{
+ sizeof(g_vs20_standardvs),
+ sizeof(g_vs20_flipyvs),
+ sizeof(g_ps20_passthroughps),
+ sizeof(g_ps20_luminanceps),
+ sizeof(g_ps20_componentmaskps)
+};
+}
+
+namespace rx
+{
+Blit::Blit(rx::Renderer9 *renderer)
+ : mRenderer(renderer), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedStateBlock(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL)
+{
+ initGeometry();
+ memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
+}
+
+Blit::~Blit()
+{
+ if (mSavedStateBlock) mSavedStateBlock->Release();
+ if (mQuadVertexBuffer) mQuadVertexBuffer->Release();
+ if (mQuadVertexDeclaration) mQuadVertexDeclaration->Release();
+
+ for (int i = 0; i < SHADER_COUNT; i++)
+ {
+ if (mCompiledShaders[i])
+ {
+ mCompiledShaders[i]->Release();
+ }
+ }
+}
+
+void Blit::initGeometry()
+{
+ static const float quad[] =
+ {
+ -1, -1,
+ -1, 1,
+ 1, -1,
+ 1, 1
+ };
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ void *lockPtr = NULL;
+ result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
+
+ if (FAILED(result) || lockPtr == NULL)
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ memcpy(lockPtr, quad, sizeof(quad));
+ mQuadVertexBuffer->Unlock();
+
+ static const D3DVERTEXELEMENT9 elements[] =
+ {
+ { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
+ D3DDECL_END()
+ };
+
+ result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+}
+
+template <class D3DShaderType>
+bool Blit::setShader(ShaderId source, const char *profile,
+ D3DShaderType *(rx::Renderer9::*createShader)(const DWORD *, size_t length),
+ HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DShaderType *shader;
+
+ if (mCompiledShaders[source] != NULL)
+ {
+ shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
+ }
+ else
+ {
+ const BYTE* shaderCode = g_shaderCode[source];
+ size_t shaderSize = g_shaderSize[source];
+
+ shader = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize);
+ if (!shader)
+ {
+ ERR("Failed to create shader for blit operation");
+ return false;
+ }
+
+ mCompiledShaders[source] = shader;
+ }
+
+ HRESULT hr = (device->*setShader)(shader);
+
+ if (FAILED(hr))
+ {
+ ERR("Failed to set shader for blit operation");
+ return false;
+ }
+
+ return true;
+}
+
+bool Blit::setVertexShader(ShaderId shader)
+{
+ return setShader<IDirect3DVertexShader9>(shader, "vs_2_0", &rx::Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader);
+}
+
+bool Blit::setPixelShader(ShaderId shader)
+{
+ return setShader<IDirect3DPixelShader9>(shader, "ps_2_0", &rx::Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader);
+}
+
+RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const
+{
+ D3DSURFACE_DESC desc;
+ surface->GetDesc(&desc);
+
+ RECT rect;
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = desc.Width;
+ rect.bottom = desc.Height;
+
+ return rect;
+}
+
+bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
+{
+ IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source));
+ if (!texture)
+ {
+ return false;
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ saveState();
+
+ device->SetTexture(0, texture);
+ device->SetRenderTarget(0, dest);
+
+ setVertexShader(SHADER_VS_STANDARD);
+ setPixelShader(SHADER_PS_PASSTHROUGH);
+
+ setCommonBlitState();
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+
+ setViewport(getSurfaceRect(dest), 0, 0);
+
+ render();
+
+ texture->Release();
+
+ restoreState();
+
+ return true;
+}
+
+bool Blit::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level)
+{
+ RenderTarget9 *renderTarget = NULL;
+ IDirect3DSurface9 *source = NULL;
+ gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0);
+
+ if (colorbuffer)
+ {
+ renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget());
+ }
+
+ if (renderTarget)
+ {
+ source = renderTarget->getSurface();
+ }
+
+ if (!source)
+ {
+ ERR("Failed to retrieve the render target.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance());
+ IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(level, true);
+ bool result = false;
+
+ if (destSurface)
+ {
+ result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
+ destSurface->Release();
+ }
+
+ source->Release();
+ return result;
+}
+
+bool Blit::copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level)
+{
+ RenderTarget9 *renderTarget = NULL;
+ IDirect3DSurface9 *source = NULL;
+ gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0);
+
+ if (colorbuffer)
+ {
+ renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget());
+ }
+
+ if (renderTarget)
+ {
+ source = renderTarget->getSurface();
+ }
+
+ if (!source)
+ {
+ ERR("Failed to retrieve the render target.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance());
+ IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(target, level, true);
+ bool result = false;
+
+ if (destSurface)
+ {
+ result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface);
+ destSurface->Release();
+ }
+
+ source->Release();
+ return result;
+}
+
+bool Blit::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
+{
+ if (!dest)
+ {
+ return false;
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DSURFACE_DESC sourceDesc;
+ D3DSURFACE_DESC destDesc;
+ source->GetDesc(&sourceDesc);
+ dest->GetDesc(&destDesc);
+
+ if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET &&
+ d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect
+ {
+ RECT destRect = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (sourceRect.bottom - sourceRect.top)};
+ HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+ }
+ else
+ {
+ return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest);
+ }
+ return true;
+}
+
+bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
+{
+ IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect);
+ if (!texture)
+ {
+ return false;
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ saveState();
+
+ device->SetTexture(0, texture);
+ device->SetRenderTarget(0, dest);
+
+ setViewport(sourceRect, xoffset, yoffset);
+
+ setCommonBlitState();
+ if (setFormatConvertShaders(destFormat))
+ {
+ render();
+ }
+
+ texture->Release();
+
+ restoreState();
+
+ return true;
+}
+
+bool Blit::setFormatConvertShaders(GLenum destFormat)
+{
+ bool okay = setVertexShader(SHADER_VS_STANDARD);
+
+ switch (destFormat)
+ {
+ default: UNREACHABLE();
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ case GL_RGB:
+ case GL_ALPHA:
+ okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK);
+ break;
+
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ okay = okay && setPixelShader(SHADER_PS_LUMINANCE);
+ break;
+ }
+
+ if (!okay)
+ {
+ return false;
+ }
+
+ enum { X = 0, Y = 1, Z = 2, W = 3 };
+
+ // The meaning of this constant depends on the shader that was selected.
+ // See the shader assembly code above for details.
+ float psConst0[4] = { 0, 0, 0, 0 };
+
+ switch (destFormat)
+ {
+ default: UNREACHABLE();
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ psConst0[X] = 1;
+ psConst0[Z] = 1;
+ break;
+
+ case GL_RGB:
+ psConst0[X] = 1;
+ psConst0[W] = 1;
+ break;
+
+ case GL_ALPHA:
+ psConst0[Z] = 1;
+ break;
+
+ case GL_LUMINANCE:
+ psConst0[Y] = 1;
+ break;
+
+ case GL_LUMINANCE_ALPHA:
+ psConst0[X] = 1;
+ break;
+ }
+
+ mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst0, 1);
+
+ return true;
+}
+
+IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect)
+{
+ if (!surface)
+ {
+ return NULL;
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DSURFACE_DESC sourceDesc;
+ surface->GetDesc(&sourceDesc);
+
+ // Copy the render target into a texture
+ IDirect3DTexture9 *texture;
+ HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
+ }
+
+ IDirect3DSurface9 *textureSurface;
+ result = texture->GetSurfaceLevel(0, &textureSurface);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ texture->Release();
+ return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
+ }
+
+ mRenderer->endScene();
+ result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE);
+
+ textureSurface->Release();
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ texture->Release();
+ return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
+ }
+
+ return texture;
+}
+
+void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset)
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ D3DVIEWPORT9 vp;
+ vp.X = xoffset;
+ vp.Y = yoffset;
+ vp.Width = sourceRect.right - sourceRect.left;
+ vp.Height = sourceRect.bottom - sourceRect.top;
+ vp.MinZ = 0.0f;
+ vp.MaxZ = 1.0f;
+ device->SetViewport(&vp);
+
+ float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 };
+ device->SetVertexShaderConstantF(0, halfPixelAdjust, 1);
+}
+
+void Blit::setCommonBlitState()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ device->SetDepthStencilSurface(NULL);
+
+ device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
+ device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
+ device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
+
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+
+ RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
+ device->SetScissorRect(&scissorRect);
+
+ for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ device->SetStreamSourceFreq(i, 1);
+ }
+}
+
+void Blit::render()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
+ hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
+
+ mRenderer->startScene();
+ hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+}
+
+void Blit::saveState()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ HRESULT hr;
+
+ device->GetDepthStencilSurface(&mSavedDepthStencil);
+ device->GetRenderTarget(0, &mSavedRenderTarget);
+
+ if (mSavedStateBlock == NULL)
+ {
+ hr = device->BeginStateBlock();
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+
+ setCommonBlitState();
+
+ static const float dummyConst[4] = { 0, 0, 0, 0 };
+
+ device->SetVertexShader(NULL);
+ device->SetVertexShaderConstantF(0, dummyConst, 1);
+ device->SetPixelShader(NULL);
+ device->SetPixelShaderConstantF(0, dummyConst, 1);
+
+ D3DVIEWPORT9 dummyVp;
+ dummyVp.X = 0;
+ dummyVp.Y = 0;
+ dummyVp.Width = 1;
+ dummyVp.Height = 1;
+ dummyVp.MinZ = 0;
+ dummyVp.MaxZ = 1;
+
+ device->SetViewport(&dummyVp);
+
+ device->SetTexture(0, NULL);
+
+ device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
+
+ device->SetVertexDeclaration(mQuadVertexDeclaration);
+
+ hr = device->EndStateBlock(&mSavedStateBlock);
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+ }
+
+ ASSERT(mSavedStateBlock != NULL);
+
+ if (mSavedStateBlock != NULL)
+ {
+ hr = mSavedStateBlock->Capture();
+ ASSERT(SUCCEEDED(hr));
+ }
+}
+
+void Blit::restoreState()
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ device->SetDepthStencilSurface(mSavedDepthStencil);
+ if (mSavedDepthStencil != NULL)
+ {
+ mSavedDepthStencil->Release();
+ mSavedDepthStencil = NULL;
+ }
+
+ device->SetRenderTarget(0, mSavedRenderTarget);
+ if (mSavedRenderTarget != NULL)
+ {
+ mSavedRenderTarget->Release();
+ mSavedRenderTarget = NULL;
+ }
+
+ ASSERT(mSavedStateBlock != NULL);
+
+ if (mSavedStateBlock != NULL)
+ {
+ mSavedStateBlock->Apply();
+ }
+}
+
+}
diff --git a/src/libGLESv2/renderer/Blit.h b/src/libGLESv2/renderer/Blit.h
new file mode 100644
index 00000000..3718028e
--- /dev/null
+++ b/src/libGLESv2/renderer/Blit.h
@@ -0,0 +1,94 @@
+//
+// 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.
+//
+
+// Blit.cpp: Surface copy utility class.
+
+#ifndef LIBGLESV2_BLIT_H_
+#define LIBGLESV2_BLIT_H_
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+class Framebuffer;
+}
+
+namespace rx
+{
+class Renderer9;
+class TextureStorageInterface2D;
+class TextureStorageInterfaceCube;
+
+class Blit
+{
+ public:
+ explicit Blit(Renderer9 *renderer);
+ ~Blit();
+
+ // Copy from source surface to dest surface.
+ // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left)
+ bool copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level);
+ bool copy(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *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.
+ bool formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest);
+
+ // 2x2 box filter sample from source to dest.
+ // Requires that source is RGB(A) and dest has the same format as source.
+ bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest);
+
+ private:
+ rx::Renderer9 *mRenderer;
+
+ IDirect3DVertexBuffer9 *mQuadVertexBuffer;
+ IDirect3DVertexDeclaration9 *mQuadVertexDeclaration;
+
+ void initGeometry();
+
+ bool setFormatConvertShaders(GLenum destFormat);
+
+ bool copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest);
+ IDirect3DTexture9 *copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect);
+ void setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset);
+ void setCommonBlitState();
+ RECT getSurfaceRect(IDirect3DSurface9 *surface) const;
+
+ // This enum is used to index mCompiledShaders and mShaderSource.
+ enum ShaderId
+ {
+ SHADER_VS_STANDARD,
+ SHADER_VS_FLIPY,
+ SHADER_PS_PASSTHROUGH,
+ SHADER_PS_LUMINANCE,
+ SHADER_PS_COMPONENTMASK,
+ SHADER_COUNT
+ };
+
+ // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown.
+ IUnknown *mCompiledShaders[SHADER_COUNT];
+
+ template <class D3DShaderType>
+ bool setShader(ShaderId source, const char *profile,
+ D3DShaderType *(Renderer9::*createShader)(const DWORD *, size_t length),
+ HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*));
+
+ bool setVertexShader(ShaderId shader);
+ bool setPixelShader(ShaderId shader);
+ void render();
+
+ void saveState();
+ void restoreState();
+ IDirect3DStateBlock9 *mSavedStateBlock;
+ IDirect3DSurface9 *mSavedRenderTarget;
+ IDirect3DSurface9 *mSavedDepthStencil;
+
+ DISALLOW_COPY_AND_ASSIGN(Blit);
+};
+}
+
+#endif // LIBGLESV2_BLIT_H_
diff --git a/src/libGLESv2/renderer/BufferStorage.cpp b/src/libGLESv2/renderer/BufferStorage.cpp
new file mode 100644
index 00000000..a49b7bab
--- /dev/null
+++ b/src/libGLESv2/renderer/BufferStorage.cpp
@@ -0,0 +1,40 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// BufferStorage.cpp Defines the abstract BufferStorage class.
+
+#include "libGLESv2/renderer/BufferStorage.h"
+
+namespace rx
+{
+
+unsigned int BufferStorage::mNextSerial = 1;
+
+BufferStorage::BufferStorage()
+{
+ updateSerial();
+}
+
+BufferStorage::~BufferStorage()
+{
+}
+
+unsigned int BufferStorage::getSerial() const
+{
+ return mSerial;
+}
+
+void BufferStorage::updateSerial()
+{
+ mSerial = mNextSerial++;
+}
+
+void BufferStorage::markBufferUsage()
+{
+}
+
+}
diff --git a/src/libGLESv2/renderer/BufferStorage.h b/src/libGLESv2/renderer/BufferStorage.h
new file mode 100644
index 00000000..ace1a11b
--- /dev/null
+++ b/src/libGLESv2/renderer/BufferStorage.h
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// BufferStorage.h Defines the abstract BufferStorage class.
+
+#ifndef LIBGLESV2_RENDERER_BUFFERSTORAGE_H_
+#define LIBGLESV2_RENDERER_BUFFERSTORAGE_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+
+class BufferStorage
+{
+ public:
+ BufferStorage();
+ virtual ~BufferStorage();
+
+ // The data returned is only guaranteed valid until next non-const method.
+ virtual void *getData() = 0;
+ virtual void setData(const void* data, unsigned int size, unsigned int offset) = 0;
+ virtual void clear() = 0;
+ virtual unsigned int getSize() const = 0;
+ virtual bool supportsDirectBinding() const = 0;
+ virtual void markBufferUsage();
+ unsigned int getSerial() const;
+
+ protected:
+ void updateSerial();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BufferStorage);
+
+ unsigned int mSerial;
+ static unsigned int mNextSerial;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_BUFFERSTORAGE_H_
diff --git a/src/libGLESv2/renderer/BufferStorage11.cpp b/src/libGLESv2/renderer/BufferStorage11.cpp
new file mode 100644
index 00000000..3647d8a8
--- /dev/null
+++ b/src/libGLESv2/renderer/BufferStorage11.cpp
@@ -0,0 +1,358 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// BufferStorage11.cpp Defines the BufferStorage11 class.
+
+#include "libGLESv2/renderer/BufferStorage11.h"
+#include "libGLESv2/main.h"
+#include "libGLESv2/renderer/Renderer11.h"
+
+namespace rx
+{
+
+BufferStorage11::BufferStorage11(Renderer11 *renderer)
+{
+ mRenderer = renderer;
+
+ mStagingBuffer = NULL;
+ mStagingBufferSize = 0;
+
+ mBuffer = NULL;
+ mBufferSize = 0;
+
+ mSize = 0;
+
+ mResolvedData = NULL;
+ mResolvedDataSize = 0;
+ mResolvedDataValid = false;
+
+ mReadUsageCount = 0;
+ mWriteUsageCount = 0;
+}
+
+BufferStorage11::~BufferStorage11()
+{
+ if (mStagingBuffer)
+ {
+ mStagingBuffer->Release();
+ mStagingBuffer = NULL;
+ }
+
+ if (mBuffer)
+ {
+ mBuffer->Release();
+ mBuffer = NULL;
+ }
+
+ if (mResolvedData)
+ {
+ free(mResolvedData);
+ mResolvedData = NULL;
+ }
+}
+
+BufferStorage11 *BufferStorage11::makeBufferStorage11(BufferStorage *bufferStorage)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(BufferStorage11*, bufferStorage));
+ return static_cast<BufferStorage11*>(bufferStorage);
+}
+
+void *BufferStorage11::getData()
+{
+ if (!mResolvedDataValid)
+ {
+ ID3D11Device *device = mRenderer->getDevice();
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+ HRESULT result;
+
+ if (!mStagingBuffer || mStagingBufferSize < mBufferSize)
+ {
+ if (mStagingBuffer)
+ {
+ mStagingBuffer->Release();
+ mStagingBuffer = NULL;
+ mStagingBufferSize = 0;
+ }
+
+ D3D11_BUFFER_DESC bufferDesc;
+ bufferDesc.ByteWidth = mSize;
+ bufferDesc.Usage = D3D11_USAGE_STAGING;
+ bufferDesc.BindFlags = 0;
+ bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
+ bufferDesc.MiscFlags = 0;
+ bufferDesc.StructureByteStride = 0;
+
+ result = device->CreateBuffer(&bufferDesc, NULL, &mStagingBuffer);
+ if (FAILED(result))
+ {
+ return gl::error(GL_OUT_OF_MEMORY, (void*)NULL);
+ }
+
+ mStagingBufferSize = bufferDesc.ByteWidth;
+ }
+
+ if (!mResolvedData || mResolvedDataSize < mBufferSize)
+ {
+ free(mResolvedData);
+ mResolvedData = malloc(mSize);
+ mResolvedDataSize = mSize;
+ }
+
+ D3D11_BOX srcBox;
+ srcBox.left = 0;
+ srcBox.right = mSize;
+ srcBox.top = 0;
+ srcBox.bottom = 1;
+ srcBox.front = 0;
+ srcBox.back = 1;
+
+ context->CopySubresourceRegion(mStagingBuffer, 0, 0, 0, 0, mBuffer, 0, &srcBox);
+
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ result = context->Map(mStagingBuffer, 0, D3D11_MAP_READ, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ return gl::error(GL_OUT_OF_MEMORY, (void*)NULL);
+ }
+
+ memcpy(mResolvedData, mappedResource.pData, mSize);
+
+ context->Unmap(mStagingBuffer, 0);
+
+ mResolvedDataValid = true;
+ }
+
+ mReadUsageCount = 0;
+
+ return mResolvedData;
+}
+
+void BufferStorage11::setData(const void* data, unsigned int size, unsigned int offset)
+{
+ ID3D11Device *device = mRenderer->getDevice();
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+ HRESULT result;
+
+ unsigned int requiredBufferSize = size + offset;
+ unsigned int requiredStagingSize = size;
+ bool directInitialization = offset == 0 && (!mBuffer || mBufferSize < size + offset);
+
+ if (!directInitialization)
+ {
+ if (!mStagingBuffer || mStagingBufferSize < requiredStagingSize)
+ {
+ if (mStagingBuffer)
+ {
+ mStagingBuffer->Release();
+ mStagingBuffer = NULL;
+ mStagingBufferSize = 0;
+ }
+
+ D3D11_BUFFER_DESC bufferDesc;
+ bufferDesc.ByteWidth = size;
+ bufferDesc.Usage = D3D11_USAGE_STAGING;
+ bufferDesc.BindFlags = 0;
+ bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
+ bufferDesc.MiscFlags = 0;
+ bufferDesc.StructureByteStride = 0;
+
+ if (data)
+ {
+ D3D11_SUBRESOURCE_DATA initialData;
+ initialData.pSysMem = data;
+ initialData.SysMemPitch = size;
+ initialData.SysMemSlicePitch = 0;
+
+ result = device->CreateBuffer(&bufferDesc, &initialData, &mStagingBuffer);
+ }
+ else
+ {
+ result = device->CreateBuffer(&bufferDesc, NULL, &mStagingBuffer);
+ }
+
+ if (FAILED(result))
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ mStagingBufferSize = size;
+ }
+ else if (data)
+ {
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ memcpy(mappedResource.pData, data, size);
+
+ context->Unmap(mStagingBuffer, 0);
+ }
+ }
+
+ if (!mBuffer || mBufferSize < size + offset)
+ {
+ D3D11_BUFFER_DESC bufferDesc;
+ bufferDesc.ByteWidth = requiredBufferSize;
+ bufferDesc.Usage = D3D11_USAGE_DEFAULT;
+ bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_INDEX_BUFFER;
+ bufferDesc.CPUAccessFlags = 0;
+ bufferDesc.MiscFlags = 0;
+ bufferDesc.StructureByteStride = 0;
+
+ if (directInitialization)
+ {
+ // Since the data will fill the entire buffer (being larger than the initial size and having
+ // no offset), the buffer can be initialized with the data so no staging buffer is required
+
+ // No longer need the old buffer
+ if (mBuffer)
+ {
+ mBuffer->Release();
+ mBuffer = NULL;
+ mBufferSize = 0;
+ }
+
+ if (data)
+ {
+ D3D11_SUBRESOURCE_DATA initialData;
+ initialData.pSysMem = data;
+ initialData.SysMemPitch = size;
+ initialData.SysMemSlicePitch = 0;
+
+ result = device->CreateBuffer(&bufferDesc, &initialData, &mBuffer);
+ }
+ else
+ {
+ result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer);
+ }
+
+ if (FAILED(result))
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+ else if (mBuffer && offset > 0)
+ {
+ // If offset is greater than zero and the buffer is non-null, need to preserve the data from
+ // the old buffer up to offset
+ ID3D11Buffer *newBuffer = NULL;
+
+ result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer);
+ if (FAILED(result))
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ D3D11_BOX srcBox;
+ srcBox.left = 0;
+ srcBox.right = std::min(offset, mBufferSize);
+ srcBox.top = 0;
+ srcBox.bottom = 1;
+ srcBox.front = 0;
+ srcBox.back = 1;
+
+ context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mBuffer, 0, &srcBox);
+
+ mBuffer->Release();
+ mBuffer = newBuffer;
+ }
+ else
+ {
+ // Simple case, nothing needs to be copied from the old buffer to the new one, just create
+ // a new buffer
+
+ // No longer need the old buffer
+ if (mBuffer)
+ {
+ mBuffer->Release();
+ mBuffer = NULL;
+ mBufferSize = 0;
+ }
+
+ // Create a new buffer for data storage
+ result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer);
+ if (FAILED(result))
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ updateSerial();
+ mBufferSize = bufferDesc.ByteWidth;
+ }
+
+ if (!directInitialization)
+ {
+ ASSERT(mStagingBuffer && mStagingBufferSize >= requiredStagingSize);
+
+ // Data is already put into the staging buffer, copy it over to the data buffer
+ D3D11_BOX srcBox;
+ srcBox.left = 0;
+ srcBox.right = size;
+ srcBox.top = 0;
+ srcBox.bottom = 1;
+ srcBox.front = 0;
+ srcBox.back = 1;
+
+ context->CopySubresourceRegion(mBuffer, 0, offset, 0, 0, mStagingBuffer, 0, &srcBox);
+ }
+
+ mSize = std::max(mSize, offset + size);
+
+ mWriteUsageCount = 0;
+
+ mResolvedDataValid = false;
+}
+
+void BufferStorage11::clear()
+{
+ mResolvedDataValid = false;
+ mSize = 0;
+}
+
+unsigned int BufferStorage11::getSize() const
+{
+ return mSize;
+}
+
+bool BufferStorage11::supportsDirectBinding() const
+{
+ return true;
+}
+
+void BufferStorage11::markBufferUsage()
+{
+ mReadUsageCount++;
+ mWriteUsageCount++;
+
+ static const unsigned int usageLimit = 5;
+
+ if (mReadUsageCount > usageLimit && mResolvedData)
+ {
+ free(mResolvedData);
+ mResolvedData = NULL;
+ mResolvedDataSize = 0;
+ mResolvedDataValid = false;
+ }
+
+ if (mReadUsageCount > usageLimit && mWriteUsageCount > usageLimit && mStagingBuffer)
+ {
+ mStagingBuffer->Release();
+ mStagingBuffer = NULL;
+ mStagingBufferSize = 0;
+ }
+}
+
+ID3D11Buffer *BufferStorage11::getBuffer() const
+{
+ return mBuffer;
+}
+
+}
diff --git a/src/libGLESv2/renderer/BufferStorage11.h b/src/libGLESv2/renderer/BufferStorage11.h
new file mode 100644
index 00000000..b62348b0
--- /dev/null
+++ b/src/libGLESv2/renderer/BufferStorage11.h
@@ -0,0 +1,56 @@
+//
+// 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.
+//
+
+// BufferStorage11.h Defines the BufferStorage11 class.
+
+#ifndef LIBGLESV2_RENDERER_BUFFERSTORAGE11_H_
+#define LIBGLESV2_RENDERER_BUFFERSTORAGE11_H_
+
+#include "libGLESv2/renderer/BufferStorage.h"
+
+namespace rx
+{
+class Renderer11;
+
+class BufferStorage11 : public BufferStorage
+{
+ public:
+ explicit BufferStorage11(Renderer11 *renderer);
+ virtual ~BufferStorage11();
+
+ static BufferStorage11 *makeBufferStorage11(BufferStorage *bufferStorage);
+
+ virtual void *getData();
+ virtual void setData(const void* data, unsigned int size, unsigned int offset);
+ virtual void clear();
+ virtual unsigned int getSize() const;
+ virtual bool supportsDirectBinding() const;
+ virtual void markBufferUsage();
+
+ ID3D11Buffer *getBuffer() const;
+
+ private:
+ Renderer11 *mRenderer;
+
+ ID3D11Buffer *mStagingBuffer;
+ unsigned int mStagingBufferSize;
+
+ ID3D11Buffer *mBuffer;
+ unsigned int mBufferSize;
+
+ unsigned int mSize;
+
+ void *mResolvedData;
+ unsigned int mResolvedDataSize;
+ bool mResolvedDataValid;
+
+ unsigned int mReadUsageCount;
+ unsigned int mWriteUsageCount;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_BUFFERSTORAGE11_H_
diff --git a/src/libGLESv2/renderer/BufferStorage9.cpp b/src/libGLESv2/renderer/BufferStorage9.cpp
new file mode 100644
index 00000000..e69e7a89
--- /dev/null
+++ b/src/libGLESv2/renderer/BufferStorage9.cpp
@@ -0,0 +1,78 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// BufferStorage9.cpp Defines the BufferStorage9 class.
+
+#include "libGLESv2/renderer/BufferStorage9.h"
+#include "common/debug.h"
+
+namespace rx
+{
+
+BufferStorage9::BufferStorage9()
+{
+ mMemory = NULL;
+ mAllocatedSize = 0;
+ mSize = 0;
+}
+
+BufferStorage9::~BufferStorage9()
+{
+ delete[] mMemory;
+}
+
+BufferStorage9 *BufferStorage9::makeBufferStorage9(BufferStorage *bufferStorage)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(BufferStorage9*, bufferStorage));
+ return static_cast<BufferStorage9*>(bufferStorage);
+}
+
+void *BufferStorage9::getData()
+{
+ return mMemory;
+}
+
+void BufferStorage9::setData(const void* data, unsigned int size, unsigned int offset)
+{
+ if (!mMemory || offset + size > mAllocatedSize)
+ {
+ unsigned int newAllocatedSize = offset + size;
+ void *newMemory = new char[newAllocatedSize];
+
+ if (offset > 0 && mMemory && mAllocatedSize > 0)
+ {
+ memcpy(newMemory, mMemory, std::min(offset, mAllocatedSize));
+ }
+
+ delete[] mMemory;
+ mMemory = newMemory;
+ mAllocatedSize = newAllocatedSize;
+ }
+
+ mSize = std::max(mSize, offset + size);
+ if (data)
+ {
+ memcpy(reinterpret_cast<char*>(mMemory) + offset, data, size);
+ }
+}
+
+void BufferStorage9::clear()
+{
+ mSize = 0;
+}
+
+unsigned int BufferStorage9::getSize() const
+{
+ return mSize;
+}
+
+bool BufferStorage9::supportsDirectBinding() const
+{
+ return false;
+}
+
+}
diff --git a/src/libGLESv2/renderer/BufferStorage9.h b/src/libGLESv2/renderer/BufferStorage9.h
new file mode 100644
index 00000000..3e803969
--- /dev/null
+++ b/src/libGLESv2/renderer/BufferStorage9.h
@@ -0,0 +1,42 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// BufferStorage9.h Defines the BufferStorage9 class.
+
+#ifndef LIBGLESV2_RENDERER_BUFFERSTORAGE9_H_
+#define LIBGLESV2_RENDERER_BUFFERSTORAGE9_H_
+
+#include "libGLESv2/renderer/BufferStorage.h"
+
+namespace rx
+{
+
+class BufferStorage9 : public BufferStorage
+{
+ public:
+ BufferStorage9();
+ virtual ~BufferStorage9();
+
+ static BufferStorage9 *makeBufferStorage9(BufferStorage *bufferStorage);
+
+ virtual void *getData();
+ virtual void setData(const void* data, unsigned int size, unsigned int offset);
+ virtual void clear();
+ virtual unsigned int getSize() const;
+ virtual bool supportsDirectBinding() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BufferStorage9);
+
+ void *mMemory;
+ unsigned int mAllocatedSize;
+
+ unsigned int mSize;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_BUFFERSTORAGE9_H_
diff --git a/src/libGLESv2/renderer/Fence11.cpp b/src/libGLESv2/renderer/Fence11.cpp
new file mode 100644
index 00000000..9d11c9a0
--- /dev/null
+++ b/src/libGLESv2/renderer/Fence11.cpp
@@ -0,0 +1,134 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Fence11.cpp: Defines the rx::Fence11 class which implements rx::FenceImpl.
+
+#include "libGLESv2/renderer/Fence11.h"
+#include "libGLESv2/main.h"
+#include "libGLESv2/renderer/Renderer11.h"
+
+namespace rx
+{
+
+Fence11::Fence11(rx::Renderer11 *renderer)
+{
+ mRenderer = renderer;
+ mQuery = NULL;
+}
+
+Fence11::~Fence11()
+{
+ if (mQuery)
+ {
+ mQuery->Release();
+ mQuery = NULL;
+ }
+}
+
+GLboolean Fence11::isFence()
+{
+ // GL_NV_fence spec:
+ // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.
+ return mQuery != NULL;
+}
+
+void Fence11::setFence(GLenum condition)
+{
+ if (!mQuery)
+ {
+ D3D11_QUERY_DESC queryDesc;
+ queryDesc.Query = D3D11_QUERY_EVENT;
+ queryDesc.MiscFlags = 0;
+
+ if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery)))
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ mRenderer->getDeviceContext()->End(mQuery);
+
+ setCondition(condition);
+ setStatus(GL_FALSE);
+}
+
+GLboolean Fence11::testFence()
+{
+ if (mQuery == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION, GL_TRUE);
+ }
+
+ HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, NULL, 0, 0);
+
+ if (mRenderer->isDeviceLost())
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_TRUE);
+ }
+
+ ASSERT(result == S_OK || result == S_FALSE);
+ setStatus(result == S_OK);
+ return getStatus();
+}
+
+void Fence11::finishFence()
+{
+ if (mQuery == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ while (!testFence())
+ {
+ Sleep(0);
+ }
+}
+
+void Fence11::getFenceiv(GLenum pname, GLint *params)
+{
+ if (mQuery == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ switch (pname)
+ {
+ case GL_FENCE_STATUS_NV:
+ {
+ // GL_NV_fence spec:
+ // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV
+ // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence.
+ if (getStatus())
+ {
+ params[0] = GL_TRUE;
+ return;
+ }
+
+ HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH);
+
+ if (mRenderer->isDeviceLost())
+ {
+ params[0] = GL_TRUE;
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ ASSERT(result == S_OK || result == S_FALSE);
+ setStatus(result == S_OK);
+ params[0] = getStatus();
+
+ break;
+ }
+ case GL_FENCE_CONDITION_NV:
+ params[0] = getCondition();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ break;
+ }
+}
+
+}
diff --git a/src/libGLESv2/renderer/Fence11.h b/src/libGLESv2/renderer/Fence11.h
new file mode 100644
index 00000000..a5398bca
--- /dev/null
+++ b/src/libGLESv2/renderer/Fence11.h
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Fence11.h: Defines the rx::Fence11 class which implements rx::FenceImpl.
+
+#ifndef LIBGLESV2_RENDERER_Fence11_H_
+#define LIBGLESV2_RENDERER_Fence11_H_
+
+#include "libGLESv2/renderer/FenceImpl.h"
+
+namespace rx
+{
+class Renderer11;
+
+class Fence11 : public FenceImpl
+{
+ public:
+ explicit Fence11(rx::Renderer11 *renderer);
+ virtual ~Fence11();
+
+ GLboolean isFence();
+ void setFence(GLenum condition);
+ GLboolean testFence();
+ void finishFence();
+ void getFenceiv(GLenum pname, GLint *params);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Fence11);
+
+ rx::Renderer11 *mRenderer;
+ ID3D11Query *mQuery;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_FENCE11_H_
diff --git a/src/libGLESv2/renderer/Fence9.cpp b/src/libGLESv2/renderer/Fence9.cpp
new file mode 100644
index 00000000..86064d7e
--- /dev/null
+++ b/src/libGLESv2/renderer/Fence9.cpp
@@ -0,0 +1,135 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Fence9.cpp: Defines the rx::Fence9 class.
+
+#include "libGLESv2/renderer/Fence9.h"
+#include "libGLESv2/main.h"
+#include "libGLESv2/renderer/renderer9_utils.h"
+#include "libGLESv2/renderer/Renderer9.h"
+
+namespace rx
+{
+
+Fence9::Fence9(rx::Renderer9 *renderer)
+{
+ mRenderer = renderer;
+ mQuery = NULL;
+}
+
+Fence9::~Fence9()
+{
+ if (mQuery)
+ {
+ mRenderer->freeEventQuery(mQuery);
+ mQuery = NULL;
+ }
+}
+
+GLboolean Fence9::isFence()
+{
+ // GL_NV_fence spec:
+ // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.
+ return mQuery != NULL;
+}
+
+void Fence9::setFence(GLenum condition)
+{
+ if (!mQuery)
+ {
+ mQuery = mRenderer->allocateEventQuery();
+ if (!mQuery)
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ HRESULT result = mQuery->Issue(D3DISSUE_END);
+ ASSERT(SUCCEEDED(result));
+
+ setCondition(condition);
+ setStatus(GL_FALSE);
+}
+
+GLboolean Fence9::testFence()
+{
+ if (mQuery == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION, GL_TRUE);
+ }
+
+ HRESULT result = mQuery->GetData(NULL, 0, D3DGETDATA_FLUSH);
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ mRenderer->notifyDeviceLost();
+ return gl::error(GL_OUT_OF_MEMORY, GL_TRUE);
+ }
+
+ ASSERT(result == S_OK || result == S_FALSE);
+ setStatus(result == S_OK);
+ return getStatus();
+}
+
+void Fence9::finishFence()
+{
+ if (mQuery == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ while (!testFence())
+ {
+ Sleep(0);
+ }
+}
+
+void Fence9::getFenceiv(GLenum pname, GLint *params)
+{
+ if (mQuery == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ switch (pname)
+ {
+ case GL_FENCE_STATUS_NV:
+ {
+ // GL_NV_fence spec:
+ // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV
+ // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence.
+ if (getStatus())
+ {
+ params[0] = GL_TRUE;
+ return;
+ }
+
+ HRESULT result = mQuery->GetData(NULL, 0, 0);
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ params[0] = GL_TRUE;
+ mRenderer->notifyDeviceLost();
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ ASSERT(result == S_OK || result == S_FALSE);
+ setStatus(result == S_OK);
+ params[0] = getStatus();
+
+ break;
+ }
+ case GL_FENCE_CONDITION_NV:
+ params[0] = getCondition();
+ break;
+ default:
+ return gl::error(GL_INVALID_ENUM);
+ break;
+ }
+}
+
+}
diff --git a/src/libGLESv2/renderer/Fence9.h b/src/libGLESv2/renderer/Fence9.h
new file mode 100644
index 00000000..9f17641e
--- /dev/null
+++ b/src/libGLESv2/renderer/Fence9.h
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Fence9.h: Defines the rx::Fence9 class which implements rx::FenceImpl.
+
+#ifndef LIBGLESV2_RENDERER_FENCE9_H_
+#define LIBGLESV2_RENDERER_FENCE9_H_
+
+#include "libGLESv2/renderer/FenceImpl.h"
+
+namespace rx
+{
+class Renderer9;
+
+class Fence9 : public FenceImpl
+{
+ public:
+ explicit Fence9(rx::Renderer9 *renderer);
+ virtual ~Fence9();
+
+ GLboolean isFence();
+ void setFence(GLenum condition);
+ GLboolean testFence();
+ void finishFence();
+ void getFenceiv(GLenum pname, GLint *params);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Fence9);
+
+ rx::Renderer9 *mRenderer;
+ IDirect3DQuery9 *mQuery;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_FENCE9_H_
diff --git a/src/libGLESv2/renderer/FenceImpl.h b/src/libGLESv2/renderer/FenceImpl.h
new file mode 100644
index 00000000..d7f2102a
--- /dev/null
+++ b/src/libGLESv2/renderer/FenceImpl.h
@@ -0,0 +1,45 @@
+//
+// 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.
+//
+
+// FenceImpl.h: Defines the rx::FenceImpl class.
+
+#ifndef LIBGLESV2_RENDERER_FENCEIMPL_H_
+#define LIBGLESV2_RENDERER_FENCEIMPL_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+
+class FenceImpl
+{
+ public:
+ FenceImpl() : mStatus(GL_FALSE), mCondition(GL_NONE) { };
+ virtual ~FenceImpl() { };
+
+ virtual GLboolean isFence() = 0;
+ virtual void setFence(GLenum condition) = 0;
+ virtual GLboolean testFence() = 0;
+ virtual void finishFence() = 0;
+ virtual void getFenceiv(GLenum pname, GLint *params) = 0;
+
+ protected:
+ void setStatus(GLboolean status) { mStatus = status; }
+ GLboolean getStatus() const { return mStatus; }
+
+ void setCondition(GLuint condition) { mCondition = condition; }
+ GLuint getCondition() const { return mCondition; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FenceImpl);
+
+ GLboolean mStatus;
+ GLenum mCondition;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_FENCEIMPL_H_
diff --git a/src/libGLESv2/renderer/Image.cpp b/src/libGLESv2/renderer/Image.cpp
new file mode 100644
index 00000000..57239ef7
--- /dev/null
+++ b/src/libGLESv2/renderer/Image.cpp
@@ -0,0 +1,548 @@
+#include "precompiled.h"
+//
+// 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: Implements the rx::Image class, an abstract base class for the
+// renderer-specific classes which will define the interface to the underlying
+// surfaces or resources.
+
+#include "libGLESv2/renderer/Image.h"
+
+namespace rx
+{
+
+Image::Image()
+{
+ mWidth = 0;
+ mHeight = 0;
+ mInternalFormat = GL_NONE;
+ mActualFormat = GL_NONE;
+}
+
+void Image::loadAlphaDataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ for (int 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 Image::loadAlphaDataToNative(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ memcpy(dest, source, width);
+ }
+}
+
+void Image::loadAlphaFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ for (int 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 Image::loadAlphaHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ for (int 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 Image::loadLuminanceDataToNativeOrBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native)
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+
+ if (!native) // BGRA8 destination format
+ {
+ for (int 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] = 0xFF;
+ }
+ }
+ else // L8 destination format
+ {
+ memcpy(dest, source, width);
+ }
+ }
+}
+
+void Image::loadLuminanceFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ for (int 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 Image::loadLuminanceFloatDataToRGB(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ for (int x = 0; x < width; x++)
+ {
+ dest[3 * x + 0] = source[x];
+ dest[3 * x + 1] = source[x];
+ dest[3 * x + 2] = source[x];
+ }
+ }
+}
+
+void Image::loadLuminanceHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ for (int 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] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
+ }
+ }
+}
+
+void Image::loadLuminanceAlphaDataToNativeOrBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native)
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+
+ if (!native) // BGRA8 destination format
+ {
+ for (int 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];
+ }
+ }
+ else
+ {
+ memcpy(dest, source, width * 2);
+ }
+ }
+}
+
+void Image::loadLuminanceAlphaFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ for (int 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 Image::loadLuminanceAlphaHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ for (int 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 Image::loadRGBUByteDataToBGRX(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ for (int 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 Image::loadRGBUByteDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 3 + 0];
+ dest[4 * x + 1] = source[x * 3 + 1];
+ dest[4 * x + 2] = source[x * 3 + 2];
+ dest[4 * x + 3] = 0xFF;
+ }
+ }
+}
+
+void Image::loadRGB565DataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
+ dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
+ dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+ dest[4 * x + 3] = 0xFF;
+ }
+ }
+}
+
+void Image::loadRGB565DataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+ dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
+ dest[4 * x + 2] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
+ dest[4 * x + 3] = 0xFF;
+ }
+ }
+}
+
+void Image::loadRGBFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 3 + 0];
+ dest[4 * x + 1] = source[x * 3 + 1];
+ dest[4 * x + 2] = source[x * 3 + 2];
+ dest[4 * x + 3] = 1.0f;
+ }
+ }
+}
+
+void Image::loadRGBFloatDataToNative(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ memcpy(dest, source, width * 12);
+ }
+}
+
+void Image::loadRGBHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 3 + 0];
+ dest[4 * x + 1] = source[x * 3 + 1];
+ dest[4 * x + 2] = source[x * 3 + 2];
+ dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
+ }
+ }
+}
+
+void Image::loadRGBAUByteDataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned int *source = NULL;
+ unsigned int *dest = NULL;
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
+
+ for (int x = 0; x < width; x++)
+ {
+ unsigned int rgba = source[x];
+ dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
+ }
+ }
+}
+
+void Image::loadRGBAUByteDataToNative(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned int *source = NULL;
+ unsigned int *dest = NULL;
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
+
+ memcpy(dest, source, width * 4);
+ }
+}
+
+void Image::loadRGBA4444DataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
+ dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
+ dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
+ dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
+ }
+ }
+}
+
+void Image::loadRGBA4444DataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
+ dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
+ dest[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
+ dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
+ }
+ }
+}
+
+void Image::loadRGBA5551DataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
+ dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
+ dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+ dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
+ }
+ }
+}
+
+void Image::loadRGBA5551DataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+ dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
+ dest[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
+ dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
+ }
+ }
+}
+
+void Image::loadRGBAFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ memcpy(dest, source, width * 16);
+ }
+}
+
+void Image::loadRGBAHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ memcpy(dest, source, width * 8);
+ }
+}
+
+void Image::loadBGRADataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + y * outputPitch;
+ memcpy(dest, source, width*4);
+ }
+}
+
+}
diff --git a/src/libGLESv2/renderer/Image.h b/src/libGLESv2/renderer/Image.h
new file mode 100644
index 00000000..454e83e2
--- /dev/null
+++ b/src/libGLESv2/renderer/Image.h
@@ -0,0 +1,131 @@
+//
+// 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 LIBGLESV2_RENDERER_IMAGE_H_
+#define LIBGLESV2_RENDERER_IMAGE_H_
+
+#include "common/debug.h"
+
+namespace gl
+{
+class Framebuffer;
+}
+
+namespace rx
+{
+class Renderer;
+class TextureStorageInterface2D;
+class TextureStorageInterfaceCube;
+
+class Image
+{
+ public:
+ Image();
+ virtual ~Image() {};
+
+ GLsizei getWidth() const { return mWidth; }
+ GLsizei getHeight() const { return mHeight; }
+ GLenum getInternalFormat() const { return mInternalFormat; }
+ GLenum getActualFormat() const { return mActualFormat; }
+
+ void markDirty() {mDirty = true;}
+ void markClean() {mDirty = false;}
+ virtual bool isDirty() const = 0;
+
+ virtual void setManagedSurface(TextureStorageInterface2D *storage, int level) {};
+ virtual void setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level) {};
+ virtual bool updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0;
+ virtual bool updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0;
+
+ virtual bool redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease) = 0;
+
+ virtual bool isRenderableFormat() const = 0;
+
+ virtual void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLint unpackAlignment, const void *input) = 0;
+ virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ const void *input) = 0;
+
+ virtual void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0;
+
+ static void loadAlphaDataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadAlphaDataToNative(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadAlphaDataToBGRASSE2(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadAlphaFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadAlphaHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadLuminanceDataToNativeOrBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native);
+ static void loadLuminanceFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadLuminanceFloatDataToRGB(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadLuminanceHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadLuminanceAlphaDataToNativeOrBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native);
+ static void loadLuminanceAlphaFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadLuminanceAlphaHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBUByteDataToBGRX(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBUByteDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGB565DataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGB565DataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBFloatDataToNative(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBAUByteDataToBGRASSE2(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBAUByteDataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBAUByteDataToNative(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBA4444DataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBA4444DataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBA5551DataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBA5551DataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBAFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadRGBAHalfFloatDataToRGBA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+ static void loadBGRADataToBGRA(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output);
+
+ protected:
+ GLsizei mWidth;
+ GLsizei mHeight;
+ GLint mInternalFormat;
+ GLenum mActualFormat;
+
+ bool mDirty;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Image);
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_IMAGE_H_
diff --git a/src/libGLESv2/renderer/Image11.cpp b/src/libGLESv2/renderer/Image11.cpp
new file mode 100644
index 00000000..a46ad756
--- /dev/null
+++ b/src/libGLESv2/renderer/Image11.cpp
@@ -0,0 +1,457 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Image11.h: Implements the rx::Image11 class, which acts as the interface to
+// the actual underlying resources of a Texture
+
+#include "libGLESv2/renderer/Renderer11.h"
+#include "libGLESv2/renderer/Image11.h"
+#include "libGLESv2/renderer/TextureStorage11.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Renderbuffer.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/renderer/renderer11_utils.h"
+#include "libGLESv2/renderer/generatemip.h"
+
+namespace rx
+{
+
+Image11::Image11()
+{
+ mStagingTexture = NULL;
+ mRenderer = NULL;
+ mDXGIFormat = DXGI_FORMAT_UNKNOWN;
+}
+
+Image11::~Image11()
+{
+ if (mStagingTexture)
+ {
+ mStagingTexture->Release();
+ }
+}
+
+Image11 *Image11::makeImage11(Image *img)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img));
+ return static_cast<rx::Image11*>(img);
+}
+
+void Image11::generateMipmap(Image11 *dest, Image11 *src)
+{
+ ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
+ ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
+ ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
+
+ D3D11_MAPPED_SUBRESOURCE destMapped, srcMapped;
+ dest->map(&destMapped);
+ src->map(&srcMapped);
+
+ const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(srcMapped.pData);
+ unsigned char *destData = reinterpret_cast<unsigned char*>(destMapped.pData);
+
+ if (sourceData && destData)
+ {
+ switch (src->getDXGIFormat())
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ GenerateMip<R8G8B8A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_A8_UNORM:
+ GenerateMip<A8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_R8_UNORM:
+ GenerateMip<R8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ GenerateMip<A32B32G32R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_R32G32B32_FLOAT:
+ GenerateMip<R32G32B32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ GenerateMip<A16B16G16R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_R8G8_UNORM:
+ GenerateMip<R8G8>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_R16_FLOAT:
+ GenerateMip<R16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_R16G16_FLOAT:
+ GenerateMip<R16G16F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_R32_FLOAT:
+ GenerateMip<R32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ case DXGI_FORMAT_R32G32_FLOAT:
+ GenerateMip<R32G32F>(src->getWidth(), src->getHeight(), sourceData, srcMapped.RowPitch, destData, destMapped.RowPitch);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ dest->unmap();
+ src->unmap();
+ }
+
+ dest->markDirty();
+}
+
+bool Image11::isDirty() const
+{
+ return (mStagingTexture && mDirty);
+}
+
+bool Image11::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
+ return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, width, height);
+}
+
+bool Image11::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
+ return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, width, height);
+}
+
+bool Image11::redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
+{
+ if (mWidth != width ||
+ mHeight != height ||
+ mInternalFormat != internalformat ||
+ forceRelease)
+ {
+ mRenderer = Renderer11::makeRenderer11(renderer);
+
+ mWidth = width;
+ mHeight = height;
+ mInternalFormat = internalformat;
+ // compute the d3d format that will be used
+ mDXGIFormat = gl_d3d11::ConvertTextureFormat(internalformat);
+ mActualFormat = d3d11_gl::ConvertTextureInternalFormat(mDXGIFormat);
+
+ if (mStagingTexture)
+ {
+ mStagingTexture->Release();
+ mStagingTexture = NULL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Image11::isRenderableFormat() const
+{
+ return TextureStorage11::IsTextureFormatRenderable(mDXGIFormat);
+}
+
+DXGI_FORMAT Image11::getDXGIFormat() const
+{
+ // this should only happen if the image hasn't been redefined first
+ // which would be a bug by the caller
+ ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
+
+ return mDXGIFormat;
+}
+
+// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
+// into the target pixel rectangle.
+void Image11::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLint unpackAlignment, const void *input)
+{
+ D3D11_MAPPED_SUBRESOURCE mappedImage;
+ HRESULT result = map(&mappedImage);
+ if (FAILED(result))
+ {
+ ERR("Could not map image for loading.");
+ return;
+ }
+
+ GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
+ size_t pixelSize = d3d11::ComputePixelSizeBits(mDXGIFormat) / 8;
+ void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + (yoffset * mappedImage.RowPitch + xoffset * pixelSize));
+
+ switch (mInternalFormat)
+ {
+ case GL_ALPHA8_EXT:
+ loadAlphaDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_LUMINANCE8_EXT:
+ loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
+ break;
+ case GL_ALPHA32F_EXT:
+ loadAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_LUMINANCE32F_EXT:
+ loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_ALPHA16F_EXT:
+ loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_LUMINANCE16F_EXT:
+ loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_LUMINANCE8_ALPHA8_EXT:
+ loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData, false);
+ break;
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_RGB8_OES:
+ loadRGBUByteDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_RGB565:
+ loadRGB565DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_RGBA8_OES:
+ loadRGBAUByteDataToNative(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_RGBA4:
+ loadRGBA4444DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_RGB5_A1:
+ loadRGBA5551DataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_BGRA8_EXT:
+ loadBGRADataToBGRA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_RGB32F_EXT:
+ loadRGBFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_RGB16F_EXT:
+ loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_RGBA32F_EXT:
+ loadRGBAFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ case GL_RGBA16F_EXT:
+ loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, mappedImage.RowPitch, offsetMappedData);
+ break;
+ default: UNREACHABLE();
+ }
+
+ unmap();
+}
+
+void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ const void *input)
+{
+ ASSERT(xoffset % 4 == 0);
+ ASSERT(yoffset % 4 == 0);
+
+ D3D11_MAPPED_SUBRESOURCE mappedImage;
+ HRESULT result = map(&mappedImage);
+ if (FAILED(result))
+ {
+ ERR("Could not map image for loading.");
+ return;
+ }
+
+ // Size computation assumes a 4x4 block compressed texture format
+ size_t blockSize = d3d11::ComputeBlockSizeBits(mDXGIFormat) / 8;
+ void* offsetMappedData = (void*)((BYTE *)mappedImage.pData + ((yoffset / 4) * mappedImage.RowPitch + (xoffset / 4) * blockSize));
+
+ GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
+ GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
+ int rows = inputSize / inputPitch;
+ for (int i = 0; i < rows; ++i)
+ {
+ memcpy((void*)((BYTE*)offsetMappedData + i * mappedImage.RowPitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
+ }
+
+ unmap();
+}
+
+void Image11::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+{
+ gl::Renderbuffer *colorbuffer = source->getReadColorbuffer();
+
+ if (colorbuffer && colorbuffer->getActualFormat() == (GLuint)mActualFormat)
+ {
+ // No conversion needed-- use copyback fastpath
+ ID3D11Texture2D *colorBufferTexture = NULL;
+ unsigned int subresourceIndex = 0;
+
+ if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
+ {
+ D3D11_TEXTURE2D_DESC textureDesc;
+ colorBufferTexture->GetDesc(&textureDesc);
+
+ ID3D11Device *device = mRenderer->getDevice();
+ ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+
+ ID3D11Texture2D* srcTex = NULL;
+ if (textureDesc.SampleDesc.Count > 1)
+ {
+ D3D11_TEXTURE2D_DESC resolveDesc;
+ resolveDesc.Width = textureDesc.Width;
+ resolveDesc.Height = textureDesc.Height;
+ resolveDesc.MipLevels = 1;
+ resolveDesc.ArraySize = 1;
+ resolveDesc.Format = textureDesc.Format;
+ resolveDesc.SampleDesc.Count = 1;
+ resolveDesc.SampleDesc.Quality = 0;
+ resolveDesc.Usage = D3D11_USAGE_DEFAULT;
+ resolveDesc.BindFlags = 0;
+ resolveDesc.CPUAccessFlags = 0;
+ resolveDesc.MiscFlags = 0;
+
+ HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
+ if (FAILED(result))
+ {
+ ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
+ return;
+ }
+
+ deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
+ subresourceIndex = 0;
+ }
+ else
+ {
+ srcTex = colorBufferTexture;
+ srcTex->AddRef();
+ }
+
+ D3D11_BOX srcBox;
+ srcBox.left = x;
+ srcBox.right = x + width;
+ srcBox.top = y;
+ srcBox.bottom = y + height;
+ srcBox.front = 0;
+ srcBox.back = 1;
+
+ deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, 0, srcTex, subresourceIndex, &srcBox);
+
+ srcTex->Release();
+ colorBufferTexture->Release();
+ }
+ }
+ else
+ {
+ // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
+ D3D11_MAPPED_SUBRESOURCE mappedImage;
+ HRESULT result = map(&mappedImage);
+
+ // determine the offset coordinate into the destination buffer
+ GLsizei rowOffset = gl::ComputePixelSize(mActualFormat) * xoffset;
+ void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset;
+
+ mRenderer->readPixels(source, x, y, width, height, gl::ExtractFormat(mInternalFormat),
+ gl::ExtractType(mInternalFormat), mappedImage.RowPitch, false, 4, dataOffset);
+
+ unmap();
+ }
+}
+
+ID3D11Texture2D *Image11::getStagingTexture()
+{
+ createStagingTexture();
+
+ return mStagingTexture;
+}
+
+unsigned int Image11::getStagingSubresource()
+{
+ createStagingTexture();
+
+ return mStagingSubresource;
+}
+
+void Image11::createStagingTexture()
+{
+ if (mStagingTexture)
+ {
+ return;
+ }
+
+ ID3D11Texture2D *newTexture = NULL;
+ int lodOffset = 1;
+ const DXGI_FORMAT dxgiFormat = getDXGIFormat();
+ ASSERT(!d3d11::IsDepthStencilFormat(dxgiFormat)); // We should never get here for depth textures
+
+ if (mWidth != 0 && mHeight != 0)
+ {
+ GLsizei width = mWidth;
+ GLsizei height = mHeight;
+
+ // adjust size if needed for compressed textures
+ gl::MakeValidSize(false, d3d11::IsCompressed(dxgiFormat), &width, &height, &lodOffset);
+ ID3D11Device *device = mRenderer->getDevice();
+
+ D3D11_TEXTURE2D_DESC desc;
+ desc.Width = width;
+ desc.Height = height;
+ desc.MipLevels = lodOffset + 1;
+ desc.ArraySize = 1;
+ desc.Format = dxgiFormat;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_STAGING;
+ desc.BindFlags = 0;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+
+ HRESULT result = device->CreateTexture2D(&desc, NULL, &newTexture);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == E_OUTOFMEMORY);
+ ERR("Creating image failed.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ mStagingTexture = newTexture;
+ mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
+ mDirty = false;
+}
+
+HRESULT Image11::map(D3D11_MAPPED_SUBRESOURCE *map)
+{
+ createStagingTexture();
+
+ HRESULT result = E_FAIL;
+
+ if (mStagingTexture)
+ {
+ ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+ result = deviceContext->Map(mStagingTexture, mStagingSubresource, D3D11_MAP_WRITE, 0, map);
+
+ // this can fail if the device is removed (from TDR)
+ if (d3d11::isDeviceLostError(result))
+ {
+ mRenderer->notifyDeviceLost();
+ }
+ else if (SUCCEEDED(result))
+ {
+ mDirty = true;
+ }
+ }
+
+ return result;
+}
+
+void Image11::unmap()
+{
+ if (mStagingTexture)
+ {
+ ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+ deviceContext->Unmap(mStagingTexture, mStagingSubresource);
+ }
+}
+
+}
diff --git a/src/libGLESv2/renderer/Image11.h b/src/libGLESv2/renderer/Image11.h
new file mode 100644
index 00000000..4d5f1c17
--- /dev/null
+++ b/src/libGLESv2/renderer/Image11.h
@@ -0,0 +1,76 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Image11.h: Defines the rx::Image11 class, which acts as the interface to
+// the actual underlying resources of a Texture
+
+#ifndef LIBGLESV2_RENDERER_IMAGE11_H_
+#define LIBGLESV2_RENDERER_IMAGE11_H_
+
+#include "libGLESv2/renderer/Image.h"
+
+#include "common/debug.h"
+
+namespace gl
+{
+class Framebuffer;
+}
+
+namespace rx
+{
+class Renderer;
+class Renderer11;
+class TextureStorageInterface2D;
+class TextureStorageInterfaceCube;
+
+class Image11 : public Image
+{
+ public:
+ Image11();
+ virtual ~Image11();
+
+ static Image11 *makeImage11(Image *img);
+
+ static void generateMipmap(Image11 *dest, Image11 *src);
+
+ virtual bool isDirty() const;
+
+ virtual bool updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+ virtual bool updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+
+ virtual bool redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease);
+
+ virtual bool isRenderableFormat() const;
+ DXGI_FORMAT getDXGIFormat() const;
+
+ virtual void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLint unpackAlignment, const void *input);
+ virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ const void *input);
+
+ virtual void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+
+ protected:
+ HRESULT map(D3D11_MAPPED_SUBRESOURCE *map);
+ void unmap();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Image11);
+
+ ID3D11Texture2D *getStagingTexture();
+ unsigned int getStagingSubresource();
+ void createStagingTexture();
+
+ Renderer11 *mRenderer;
+
+ DXGI_FORMAT mDXGIFormat;
+ ID3D11Texture2D *mStagingTexture;
+ unsigned int mStagingSubresource;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_IMAGE11_H_
diff --git a/src/libGLESv2/renderer/Image9.cpp b/src/libGLESv2/renderer/Image9.cpp
new file mode 100644
index 00000000..b3dcc59b
--- /dev/null
+++ b/src/libGLESv2/renderer/Image9.cpp
@@ -0,0 +1,732 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Image9.cpp: Implements the rx::Image9 class, which acts as the interface to
+// the actual underlying surfaces of a Texture.
+
+#include "libGLESv2/renderer/Image9.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/renderer/Renderer9.h"
+#include "libGLESv2/renderer/RenderTarget9.h"
+#include "libGLESv2/renderer/TextureStorage9.h"
+
+#include "libGLESv2/renderer/renderer9_utils.h"
+#include "libGLESv2/renderer/generatemip.h"
+
+namespace rx
+{
+
+Image9::Image9()
+{
+ mSurface = NULL;
+ mRenderer = NULL;
+
+ mD3DPool = D3DPOOL_SYSTEMMEM;
+ mD3DFormat = D3DFMT_UNKNOWN;
+}
+
+Image9::~Image9()
+{
+ if (mSurface)
+ {
+ mSurface->Release();
+ }
+}
+
+void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface)
+{
+ D3DSURFACE_DESC destDesc;
+ HRESULT result = destSurface->GetDesc(&destDesc);
+ ASSERT(SUCCEEDED(result));
+
+ D3DSURFACE_DESC sourceDesc;
+ result = sourceSurface->GetDesc(&sourceDesc);
+ ASSERT(SUCCEEDED(result));
+
+ ASSERT(sourceDesc.Format == destDesc.Format);
+ ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width);
+ ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height);
+
+ D3DLOCKED_RECT sourceLocked = {0};
+ result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY);
+ ASSERT(SUCCEEDED(result));
+
+ D3DLOCKED_RECT destLocked = {0};
+ result = destSurface->LockRect(&destLocked, NULL, 0);
+ ASSERT(SUCCEEDED(result));
+
+ const unsigned char *sourceData = reinterpret_cast<const unsigned char*>(sourceLocked.pBits);
+ unsigned char *destData = reinterpret_cast<unsigned char*>(destLocked.pBits);
+
+ if (sourceData && destData)
+ {
+ switch (sourceDesc.Format)
+ {
+ case D3DFMT_L8:
+ GenerateMip<L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
+ break;
+ case D3DFMT_A8L8:
+ GenerateMip<A8L8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
+ break;
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_X8R8G8B8:
+ GenerateMip<A8R8G8B8>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
+ break;
+ case D3DFMT_A16B16G16R16F:
+ GenerateMip<A16B16G16R16F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
+ break;
+ case D3DFMT_A32B32G32R32F:
+ GenerateMip<A32B32G32R32F>(sourceDesc.Width, sourceDesc.Height, sourceData, sourceLocked.Pitch, destData, destLocked.Pitch);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ destSurface->UnlockRect();
+ sourceSurface->UnlockRect();
+ }
+}
+
+Image9 *Image9::makeImage9(Image *img)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(rx::Image9*, img));
+ return static_cast<rx::Image9*>(img);
+}
+
+void Image9::generateMipmap(Image9 *dest, Image9 *source)
+{
+ IDirect3DSurface9 *sourceSurface = source->getSurface();
+ if (sourceSurface == NULL)
+ return gl::error(GL_OUT_OF_MEMORY);
+
+ IDirect3DSurface9 *destSurface = dest->getSurface();
+ generateMip(destSurface, sourceSurface);
+
+ dest->markDirty();
+}
+
+void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source)
+{
+ D3DLOCKED_RECT sourceLock = {0};
+ D3DLOCKED_RECT destLock = {0};
+
+ source->LockRect(&sourceLock, NULL, 0);
+ dest->LockRect(&destLock, NULL, 0);
+
+ if (sourceLock.pBits && destLock.pBits)
+ {
+ D3DSURFACE_DESC desc;
+ source->GetDesc(&desc);
+
+ int rows = d3d9::IsCompressedFormat(desc.Format) ? desc.Height / 4 : desc.Height;
+ int bytes = d3d9::ComputeRowSize(desc.Format, desc.Width);
+ ASSERT(bytes <= sourceLock.Pitch && bytes <= destLock.Pitch);
+
+ for(int i = 0; i < rows; i++)
+ {
+ memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes);
+ }
+
+ source->UnlockRect();
+ dest->UnlockRect();
+ }
+ else UNREACHABLE();
+}
+
+bool Image9::redefine(rx::Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease)
+{
+ if (mWidth != width ||
+ mHeight != height ||
+ mInternalFormat != internalformat ||
+ forceRelease)
+ {
+ mRenderer = Renderer9::makeRenderer9(renderer);
+
+ mWidth = width;
+ mHeight = height;
+ mInternalFormat = internalformat;
+ // compute the d3d format that will be used
+ mD3DFormat = mRenderer->ConvertTextureInternalFormat(internalformat);
+ mActualFormat = d3d9_gl::GetEquivalentFormat(mD3DFormat);
+
+ if (mSurface)
+ {
+ mSurface->Release();
+ mSurface = NULL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void Image9::createSurface()
+{
+ if(mSurface)
+ {
+ return;
+ }
+
+ IDirect3DTexture9 *newTexture = NULL;
+ IDirect3DSurface9 *newSurface = NULL;
+ const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM;
+ const D3DFORMAT d3dFormat = getD3DFormat();
+ ASSERT(d3dFormat != D3DFMT_INTZ); // We should never get here for depth textures
+
+ if (mWidth != 0 && mHeight != 0)
+ {
+ int levelToFetch = 0;
+ GLsizei requestWidth = mWidth;
+ GLsizei requestHeight = mHeight;
+ gl::MakeValidSize(true, gl::IsCompressed(mInternalFormat), &requestWidth, &requestHeight, &levelToFetch);
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat,
+ poolToUse, &newTexture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ ERR("Creating image surface failed.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
+ newTexture->Release();
+ }
+
+ mSurface = newSurface;
+ mDirty = false;
+ mD3DPool = poolToUse;
+}
+
+HRESULT Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect)
+{
+ createSurface();
+
+ HRESULT result = D3DERR_INVALIDCALL;
+
+ if (mSurface)
+ {
+ result = mSurface->LockRect(lockedRect, rect, 0);
+ ASSERT(SUCCEEDED(result));
+
+ mDirty = true;
+ }
+
+ return result;
+}
+
+void Image9::unlock()
+{
+ if (mSurface)
+ {
+ HRESULT result = mSurface->UnlockRect();
+ ASSERT(SUCCEEDED(result));
+ }
+}
+
+bool Image9::isRenderableFormat() const
+{
+ return TextureStorage9::IsTextureFormatRenderable(getD3DFormat());
+}
+
+D3DFORMAT Image9::getD3DFormat() const
+{
+ // this should only happen if the image hasn't been redefined first
+ // which would be a bug by the caller
+ ASSERT(mD3DFormat != D3DFMT_UNKNOWN);
+
+ return mD3DFormat;
+}
+
+IDirect3DSurface9 *Image9::getSurface()
+{
+ createSurface();
+
+ return mSurface;
+}
+
+void Image9::setManagedSurface(TextureStorageInterface2D *storage, int level)
+{
+ TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance());
+ setManagedSurface(storage9->getSurfaceLevel(level, false));
+}
+
+void Image9::setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level)
+{
+ TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance());
+ setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false));
+}
+
+void Image9::setManagedSurface(IDirect3DSurface9 *surface)
+{
+ D3DSURFACE_DESC desc;
+ surface->GetDesc(&desc);
+ ASSERT(desc.Pool == D3DPOOL_MANAGED);
+
+ if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
+ {
+ if (mSurface)
+ {
+ copyLockableSurfaces(surface, mSurface);
+ mSurface->Release();
+ }
+
+ mSurface = surface;
+ mD3DPool = desc.Pool;
+ }
+}
+
+bool Image9::updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ ASSERT(getSurface() != NULL);
+ TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage->getStorageInstance());
+ return updateSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height);
+}
+
+bool Image9::updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ ASSERT(getSurface() != NULL);
+ TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage->getStorageInstance());
+ return updateSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height);
+}
+
+bool Image9::updateSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ if (!destSurface)
+ return false;
+
+ IDirect3DSurface9 *sourceSurface = getSurface();
+
+ if (sourceSurface && sourceSurface != destSurface)
+ {
+ RECT rect;
+ rect.left = xoffset;
+ rect.top = yoffset;
+ rect.right = xoffset + width;
+ rect.bottom = yoffset + height;
+
+ POINT point = {rect.left, rect.top};
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ if (mD3DPool == D3DPOOL_MANAGED)
+ {
+ D3DSURFACE_DESC desc;
+ sourceSurface->GetDesc(&desc);
+
+ IDirect3DSurface9 *surf = 0;
+ HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
+
+ if (SUCCEEDED(result))
+ {
+ copyLockableSurfaces(surf, sourceSurface);
+ result = device->UpdateSurface(surf, &rect, destSurface, &point);
+ ASSERT(SUCCEEDED(result));
+ surf->Release();
+ }
+ }
+ else
+ {
+ // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools
+ HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point);
+ ASSERT(SUCCEEDED(result));
+ }
+ }
+
+ destSurface->Release();
+ return true;
+}
+
+// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
+// into the target pixel rectangle.
+void Image9::loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLint unpackAlignment, const void *input)
+{
+ RECT lockRect =
+ {
+ xoffset, yoffset,
+ xoffset + width, yoffset + height
+ };
+
+ D3DLOCKED_RECT locked;
+ HRESULT result = lock(&locked, &lockRect);
+ if (FAILED(result))
+ {
+ return;
+ }
+
+
+ GLsizei inputPitch = gl::ComputePitch(width, mInternalFormat, unpackAlignment);
+
+ switch (mInternalFormat)
+ {
+ case GL_ALPHA8_EXT:
+ if (gl::supportsSSE2())
+ {
+ loadAlphaDataToBGRASSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ }
+ else
+ {
+ loadAlphaDataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ }
+ break;
+ case GL_LUMINANCE8_EXT:
+ loadLuminanceDataToNativeOrBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_L8);
+ break;
+ case GL_ALPHA32F_EXT:
+ loadAlphaFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_LUMINANCE32F_EXT:
+ loadLuminanceFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_ALPHA16F_EXT:
+ loadAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_LUMINANCE16F_EXT:
+ loadLuminanceHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_LUMINANCE8_ALPHA8_EXT:
+ loadLuminanceAlphaDataToNativeOrBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits, getD3DFormat() == D3DFMT_A8L8);
+ break;
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ loadLuminanceAlphaFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ loadLuminanceAlphaHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_RGB8_OES:
+ loadRGBUByteDataToBGRX(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_RGB565:
+ loadRGB565DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_RGBA8_OES:
+ if (gl::supportsSSE2())
+ {
+ loadRGBAUByteDataToBGRASSE2(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ }
+ else
+ {
+ loadRGBAUByteDataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ }
+ break;
+ case GL_RGBA4:
+ loadRGBA4444DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_RGB5_A1:
+ loadRGBA5551DataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_BGRA8_EXT:
+ loadBGRADataToBGRA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
+ case GL_RGB32F_EXT:
+ loadRGBFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_RGB16F_EXT:
+ loadRGBHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_RGBA32F_EXT:
+ loadRGBAFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ case GL_RGBA16F_EXT:
+ loadRGBAHalfFloatDataToRGBA(width, height, inputPitch, input, locked.Pitch, locked.pBits);
+ break;
+ default: UNREACHABLE();
+ }
+
+ unlock();
+}
+
+void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ const void *input)
+{
+ ASSERT(xoffset % 4 == 0);
+ ASSERT(yoffset % 4 == 0);
+
+ RECT lockRect = {
+ xoffset, yoffset,
+ xoffset + width, yoffset + height
+ };
+
+ D3DLOCKED_RECT locked;
+ HRESULT result = lock(&locked, &lockRect);
+ if (FAILED(result))
+ {
+ return;
+ }
+
+ GLsizei inputSize = gl::ComputeCompressedSize(width, height, mInternalFormat);
+ GLsizei inputPitch = gl::ComputeCompressedPitch(width, mInternalFormat);
+ int rows = inputSize / inputPitch;
+ for (int i = 0; i < rows; ++i)
+ {
+ memcpy((void*)((BYTE*)locked.pBits + i * locked.Pitch), (void*)((BYTE*)input + i * inputPitch), inputPitch);
+ }
+
+ unlock();
+}
+
+// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
+void Image9::copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+{
+ RenderTarget9 *renderTarget = NULL;
+ IDirect3DSurface9 *surface = NULL;
+ gl::Renderbuffer *colorbuffer = source->getColorbuffer(0);
+
+ if (colorbuffer)
+ {
+ renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget());
+ }
+
+ if (renderTarget)
+ {
+ surface = renderTarget->getSurface();
+ }
+
+ if (!surface)
+ {
+ ERR("Failed to retrieve the render target.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ IDirect3DSurface9 *renderTargetData = NULL;
+ D3DSURFACE_DESC description;
+ surface->GetDesc(&description);
+
+ HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Could not create matching destination surface.");
+ surface->Release();
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ result = device->GetRenderTargetData(surface, renderTargetData);
+
+ if (FAILED(result))
+ {
+ ERR("GetRenderTargetData unexpectedly failed.");
+ renderTargetData->Release();
+ surface->Release();
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ RECT sourceRect = {x, y, x + width, y + height};
+ RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
+
+ D3DLOCKED_RECT sourceLock = {0};
+ result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Failed to lock the source surface (rectangle might be invalid).");
+ renderTargetData->Release();
+ surface->Release();
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ D3DLOCKED_RECT destLock = {0};
+ result = lock(&destLock, &destRect);
+
+ if (FAILED(result))
+ {
+ ERR("Failed to lock the destination surface (rectangle might be invalid).");
+ renderTargetData->UnlockRect();
+ renderTargetData->Release();
+ surface->Release();
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ if (destLock.pBits && sourceLock.pBits)
+ {
+ unsigned char *source = (unsigned char*)sourceLock.pBits;
+ unsigned char *dest = (unsigned char*)destLock.pBits;
+
+ switch (description.Format)
+ {
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A8R8G8B8:
+ switch(getD3DFormat())
+ {
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A8R8G8B8:
+ for(int y = 0; y < height; y++)
+ {
+ memcpy(dest, source, 4 * width);
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ dest[x] = source[x * 4 + 2];
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ dest[x * 2 + 0] = source[x * 4 + 2];
+ dest[x * 2 + 1] = source[x * 4 + 3];
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case D3DFMT_R5G6B5:
+ switch(getD3DFormat())
+ {
+ case D3DFMT_X8R8G8B8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned short rgb = ((unsigned short*)source)[x];
+ unsigned char red = (rgb & 0xF800) >> 8;
+ unsigned char green = (rgb & 0x07E0) >> 3;
+ unsigned char blue = (rgb & 0x001F) << 3;
+ dest[x + 0] = blue | (blue >> 5);
+ dest[x + 1] = green | (green >> 6);
+ dest[x + 2] = red | (red >> 5);
+ dest[x + 3] = 0xFF;
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned char red = source[x * 2 + 1] & 0xF8;
+ dest[x] = red | (red >> 5);
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case D3DFMT_A1R5G5B5:
+ switch(getD3DFormat())
+ {
+ case D3DFMT_X8R8G8B8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned short argb = ((unsigned short*)source)[x];
+ unsigned char red = (argb & 0x7C00) >> 7;
+ unsigned char green = (argb & 0x03E0) >> 2;
+ unsigned char blue = (argb & 0x001F) << 3;
+ dest[x + 0] = blue | (blue >> 5);
+ dest[x + 1] = green | (green >> 5);
+ dest[x + 2] = red | (red >> 5);
+ dest[x + 3] = 0xFF;
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8R8G8B8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned short argb = ((unsigned short*)source)[x];
+ unsigned char red = (argb & 0x7C00) >> 7;
+ unsigned char green = (argb & 0x03E0) >> 2;
+ unsigned char blue = (argb & 0x001F) << 3;
+ unsigned char alpha = (signed short)argb >> 15;
+ dest[x + 0] = blue | (blue >> 5);
+ dest[x + 1] = green | (green >> 5);
+ dest[x + 2] = red | (red >> 5);
+ dest[x + 3] = alpha;
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned char red = source[x * 2 + 1] & 0x7C;
+ dest[x] = (red << 1) | (red >> 4);
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned char red = source[x * 2 + 1] & 0x7C;
+ dest[x * 2 + 0] = (red << 1) | (red >> 4);
+ dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ unlock();
+ renderTargetData->UnlockRect();
+
+ renderTargetData->Release();
+ surface->Release();
+
+ mDirty = true;
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/Image9.h b/src/libGLESv2/renderer/Image9.h
new file mode 100644
index 00000000..2fbbca31
--- /dev/null
+++ b/src/libGLESv2/renderer/Image9.h
@@ -0,0 +1,79 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Image9.h: Defines the rx::Image9 class, which acts as the interface to
+// the actual underlying surfaces of a Texture.
+
+#ifndef LIBGLESV2_RENDERER_IMAGE9_H_
+#define LIBGLESV2_RENDERER_IMAGE9_H_
+
+#include "libGLESv2/renderer/Image.h"
+#include "common/debug.h"
+
+namespace gl
+{
+class Framebuffer;
+}
+
+namespace rx
+{
+class Renderer;
+class Renderer9;
+class TextureStorageInterface2D;
+class TextureStorageInterfaceCube;
+
+class Image9 : public Image
+{
+ public:
+ Image9();
+ ~Image9();
+
+ static Image9 *makeImage9(Image *img);
+
+ static void generateMipmap(Image9 *dest, Image9 *source);
+ static void generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface);
+ static void copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source);
+
+ virtual bool redefine(Renderer *renderer, GLint internalformat, GLsizei width, GLsizei height, bool forceRelease);
+
+ virtual bool isRenderableFormat() const;
+ D3DFORMAT getD3DFormat() const;
+
+ virtual bool isDirty() const {return mSurface && mDirty;}
+ IDirect3DSurface9 *getSurface();
+
+ virtual void setManagedSurface(TextureStorageInterface2D *storage, int level);
+ virtual void setManagedSurface(TextureStorageInterfaceCube *storage, int face, int level);
+ virtual bool updateSurface(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+ virtual bool updateSurface(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+
+ virtual void loadData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLint unpackAlignment, const void *input);
+ virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ const void *input);
+
+ virtual void copy(GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Image9);
+
+ void createSurface();
+ void setManagedSurface(IDirect3DSurface9 *surface);
+ bool updateSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+
+ HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect);
+ void unlock();
+
+ Renderer9 *mRenderer;
+
+ D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable.
+ D3DFORMAT mD3DFormat;
+
+ IDirect3DSurface9 *mSurface;
+};
+}
+
+#endif // LIBGLESV2_RENDERER_IMAGE9_H_
diff --git a/src/libGLESv2/renderer/ImageSSE2.cpp b/src/libGLESv2/renderer/ImageSSE2.cpp
new file mode 100644
index 00000000..b2a90ca9
--- /dev/null
+++ b/src/libGLESv2/renderer/ImageSSE2.cpp
@@ -0,0 +1,100 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// ImageSSE2.cpp: Implements SSE2-based functions of rx::Image class. 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 "libGLESv2/Texture.h"
+#include "libGLESv2/renderer/Image.h"
+
+namespace rx
+{
+
+void Image::loadRGBAUByteDataToBGRASSE2(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned int *source = NULL;
+ unsigned int *dest = NULL;
+ __m128i brMask = _mm_set1_epi32(0x00ff00ff);
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
+ int x = 0;
+
+ // Make output writes aligned
+ for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
+ {
+ unsigned int rgba = source[x];
+ dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
+ }
+
+ for (; x + 3 < width; x += 4)
+ {
+ __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&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++)
+ {
+ unsigned int rgba = source[x];
+ dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
+ }
+ }
+}
+
+void Image::loadAlphaDataToBGRASSE2(GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output)
+{
+ const unsigned char *source = NULL;
+ unsigned int *dest = NULL;
+ __m128i zeroWide = _mm_setzero_si128();
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + y * outputPitch);
+
+ int x;
+ // Make output writes aligned
+ for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 0xF) != 0 && x < width); x++)
+ {
+ dest[x] = static_cast<unsigned int>(source[x]) << 24;
+ }
+
+ for (; x + 7 < width; x += 8)
+ {
+ __m128i sourceData = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&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<unsigned int>(source[x]) << 24;
+ }
+ }
+}
+
+}
diff --git a/src/libGLESv2/renderer/IndexBuffer.cpp b/src/libGLESv2/renderer/IndexBuffer.cpp
new file mode 100644
index 00000000..2ac94466
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexBuffer.cpp
@@ -0,0 +1,185 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexBuffer.cpp: Defines the abstract IndexBuffer class and IndexBufferInterface
+// class with derivations, classes that perform graphics API agnostic index buffer operations.
+
+#include "libGLESv2/renderer/IndexBuffer.h"
+#include "libGLESv2/renderer/Renderer.h"
+
+namespace rx
+{
+
+unsigned int IndexBuffer::mNextSerial = 1;
+
+IndexBuffer::IndexBuffer()
+{
+ updateSerial();
+}
+
+IndexBuffer::~IndexBuffer()
+{
+}
+
+unsigned int IndexBuffer::getSerial() const
+{
+ return mSerial;
+}
+
+void IndexBuffer::updateSerial()
+{
+ mSerial = mNextSerial++;
+}
+
+
+IndexBufferInterface::IndexBufferInterface(Renderer *renderer, bool dynamic) : mRenderer(renderer)
+{
+ mIndexBuffer = renderer->createIndexBuffer();
+
+ mDynamic = dynamic;
+ mWritePosition = 0;
+}
+
+IndexBufferInterface::~IndexBufferInterface()
+{
+ if (mIndexBuffer)
+ {
+ delete mIndexBuffer;
+ }
+}
+
+GLenum IndexBufferInterface::getIndexType() const
+{
+ return mIndexBuffer->getIndexType();
+}
+
+unsigned int IndexBufferInterface::getBufferSize() const
+{
+ return mIndexBuffer->getBufferSize();
+}
+
+unsigned int IndexBufferInterface::getSerial() const
+{
+ return mIndexBuffer->getSerial();
+}
+
+int IndexBufferInterface::mapBuffer(unsigned int size, void** outMappedMemory)
+{
+ if (!mIndexBuffer->mapBuffer(mWritePosition, size, outMappedMemory))
+ {
+ *outMappedMemory = NULL;
+ return -1;
+ }
+
+ int oldWritePos = static_cast<int>(mWritePosition);
+ mWritePosition += size;
+
+ return oldWritePos;
+}
+
+bool IndexBufferInterface::unmapBuffer()
+{
+ return mIndexBuffer->unmapBuffer();
+}
+
+IndexBuffer * IndexBufferInterface::getIndexBuffer() const
+{
+ return mIndexBuffer;
+}
+
+unsigned int IndexBufferInterface::getWritePosition() const
+{
+ return mWritePosition;
+}
+
+void IndexBufferInterface::setWritePosition(unsigned int writePosition)
+{
+ mWritePosition = writePosition;
+}
+
+bool IndexBufferInterface::discard()
+{
+ return mIndexBuffer->discard();
+}
+
+bool IndexBufferInterface::setBufferSize(unsigned int bufferSize, GLenum indexType)
+{
+ if (mIndexBuffer->getBufferSize() == 0)
+ {
+ return mIndexBuffer->initialize(bufferSize, indexType, mDynamic);
+ }
+ else
+ {
+ return mIndexBuffer->setSize(bufferSize, indexType);
+ }
+}
+
+StreamingIndexBufferInterface::StreamingIndexBufferInterface(Renderer *renderer) : IndexBufferInterface(renderer, true)
+{
+}
+
+StreamingIndexBufferInterface::~StreamingIndexBufferInterface()
+{
+}
+
+bool StreamingIndexBufferInterface::reserveBufferSpace(unsigned int size, GLenum indexType)
+{
+ bool result = true;
+ unsigned int curBufferSize = getBufferSize();
+ unsigned int writePos = getWritePosition();
+ if (size > curBufferSize)
+ {
+ result = setBufferSize(std::max(size, 2 * curBufferSize), indexType);
+ setWritePosition(0);
+ }
+ else if (writePos + size > curBufferSize || writePos + size < writePos)
+ {
+ if (!discard())
+ {
+ return false;
+ }
+ setWritePosition(0);
+ }
+
+ return result;
+}
+
+
+StaticIndexBufferInterface::StaticIndexBufferInterface(Renderer *renderer) : IndexBufferInterface(renderer, false)
+{
+}
+
+StaticIndexBufferInterface::~StaticIndexBufferInterface()
+{
+}
+
+bool StaticIndexBufferInterface::reserveBufferSpace(unsigned int size, GLenum indexType)
+{
+ unsigned int curSize = getBufferSize();
+ if (curSize == 0)
+ {
+ return setBufferSize(size, indexType);
+ }
+ else if (curSize >= size && indexType == getIndexType())
+ {
+ return true;
+ }
+ else
+ {
+ ERR("Static index buffers can't be resized");
+ UNREACHABLE();
+ return false;
+ }
+}
+
+IndexRangeCache *StaticIndexBufferInterface::getIndexRangeCache()
+{
+ return &mIndexRangeCache;
+}
+
+}
+
diff --git a/src/libGLESv2/renderer/IndexBuffer.h b/src/libGLESv2/renderer/IndexBuffer.h
new file mode 100644
index 00000000..98fa5fe3
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexBuffer.h
@@ -0,0 +1,111 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexBuffer.h: Defines the abstract IndexBuffer class and IndexBufferInterface
+// class with derivations, classes that perform graphics API agnostic index buffer operations.
+
+#ifndef LIBGLESV2_RENDERER_INDEXBUFFER_H_
+#define LIBGLESV2_RENDERER_INDEXBUFFER_H_
+
+#include "common/angleutils.h"
+#include "libGLESv2/renderer/IndexRangeCache.h"
+
+namespace rx
+{
+class Renderer;
+
+class IndexBuffer
+{
+ public:
+ IndexBuffer();
+ virtual ~IndexBuffer();
+
+ virtual bool initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) = 0;
+
+ virtual bool mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) = 0;
+ virtual bool unmapBuffer() = 0;
+
+ virtual bool discard() = 0;
+
+ virtual GLenum getIndexType() const = 0;
+ virtual unsigned int getBufferSize() const = 0;
+ virtual bool setSize(unsigned int bufferSize, GLenum indexType) = 0;
+
+ unsigned int getSerial() const;
+
+ protected:
+ void updateSerial();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexBuffer);
+
+ unsigned int mSerial;
+ static unsigned int mNextSerial;
+};
+
+class IndexBufferInterface
+{
+ public:
+ IndexBufferInterface(Renderer *renderer, bool dynamic);
+ virtual ~IndexBufferInterface();
+
+ virtual bool reserveBufferSpace(unsigned int size, GLenum indexType) = 0;
+
+ GLenum getIndexType() const;
+ unsigned int getBufferSize() const;
+
+ unsigned int getSerial() const;
+
+ int mapBuffer(unsigned int size, void** outMappedMemory);
+ bool unmapBuffer();
+
+ IndexBuffer *getIndexBuffer() const;
+
+ protected:
+ unsigned int getWritePosition() const;
+ void setWritePosition(unsigned int writePosition);
+
+ bool discard();
+
+ bool setBufferSize(unsigned int bufferSize, GLenum indexType);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexBufferInterface);
+
+ rx::Renderer *const mRenderer;
+
+ IndexBuffer* mIndexBuffer;
+
+ unsigned int mWritePosition;
+ bool mDynamic;
+};
+
+class StreamingIndexBufferInterface : public IndexBufferInterface
+{
+ public:
+ StreamingIndexBufferInterface(Renderer *renderer);
+ ~StreamingIndexBufferInterface();
+
+ virtual bool reserveBufferSpace(unsigned int size, GLenum indexType);
+};
+
+class StaticIndexBufferInterface : public IndexBufferInterface
+{
+ public:
+ explicit StaticIndexBufferInterface(Renderer *renderer);
+ ~StaticIndexBufferInterface();
+
+ virtual bool reserveBufferSpace(unsigned int size, GLenum indexType);
+
+ IndexRangeCache *getIndexRangeCache();
+
+ private:
+ IndexRangeCache mIndexRangeCache;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_INDEXBUFFER_H_ \ No newline at end of file
diff --git a/src/libGLESv2/renderer/IndexBuffer11.cpp b/src/libGLESv2/renderer/IndexBuffer11.cpp
new file mode 100644
index 00000000..2a442ecd
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexBuffer11.cpp
@@ -0,0 +1,182 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexBuffer11.cpp: Defines the D3D11 IndexBuffer implementation.
+
+#include "libGLESv2/renderer/IndexBuffer11.h"
+#include "libGLESv2/renderer/Renderer11.h"
+
+namespace rx
+{
+
+IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) : mRenderer(renderer)
+{
+ mBuffer = NULL;
+ mBufferSize = 0;
+ mDynamicUsage = false;
+}
+
+IndexBuffer11::~IndexBuffer11()
+{
+ if (mBuffer)
+ {
+ mBuffer->Release();
+ mBuffer = NULL;
+ }
+}
+
+bool IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic)
+{
+ if (mBuffer)
+ {
+ mBuffer->Release();
+ mBuffer = NULL;
+ }
+
+ updateSerial();
+
+ if (bufferSize > 0)
+ {
+ ID3D11Device* dxDevice = mRenderer->getDevice();
+
+ D3D11_BUFFER_DESC bufferDesc;
+ bufferDesc.ByteWidth = bufferSize;
+ bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
+ bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ bufferDesc.MiscFlags = 0;
+ bufferDesc.StructureByteStride = 0;
+
+ HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer);
+ if (FAILED(result))
+ {
+ return false;
+ }
+ }
+
+ mBufferSize = bufferSize;
+ mIndexType = indexType;
+ mDynamicUsage = dynamic;
+
+ return true;
+}
+
+IndexBuffer11 *IndexBuffer11::makeIndexBuffer11(IndexBuffer *indexBuffer)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer11*, indexBuffer));
+ return static_cast<IndexBuffer11*>(indexBuffer);
+}
+
+bool IndexBuffer11::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory)
+{
+ if (mBuffer)
+ {
+ if (offset + size > mBufferSize)
+ {
+ ERR("Index buffer map range is not inside the buffer.");
+ return false;
+ }
+
+ ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext();
+
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ ERR("Index buffer map failed with error 0x%08x", result);
+ return false;
+ }
+
+ *outMappedMemory = reinterpret_cast<char*>(mappedResource.pData) + offset;
+ return true;
+ }
+ else
+ {
+ ERR("Index buffer not initialized.");
+ return false;
+ }
+}
+
+bool IndexBuffer11::unmapBuffer()
+{
+ if (mBuffer)
+ {
+ ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext();
+ dxContext->Unmap(mBuffer, 0);
+ return true;
+ }
+ else
+ {
+ ERR("Index buffer not initialized.");
+ return false;
+ }
+}
+
+GLenum IndexBuffer11::getIndexType() const
+{
+ return mIndexType;
+}
+
+unsigned int IndexBuffer11::getBufferSize() const
+{
+ return mBufferSize;
+}
+
+bool IndexBuffer11::setSize(unsigned int bufferSize, GLenum indexType)
+{
+ if (bufferSize > mBufferSize || indexType != mIndexType)
+ {
+ return initialize(bufferSize, indexType, mDynamicUsage);
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool IndexBuffer11::discard()
+{
+ if (mBuffer)
+ {
+ ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext();
+
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ ERR("Index buffer map failed with error 0x%08x", result);
+ return false;
+ }
+
+ dxContext->Unmap(mBuffer, 0);
+
+ return true;
+ }
+ else
+ {
+ ERR("Index buffer not initialized.");
+ return false;
+ }
+}
+
+DXGI_FORMAT IndexBuffer11::getIndexFormat() const
+{
+ switch (mIndexType)
+ {
+ case GL_UNSIGNED_BYTE: return DXGI_FORMAT_R16_UINT;
+ case GL_UNSIGNED_SHORT: return DXGI_FORMAT_R16_UINT;
+ case GL_UNSIGNED_INT: return DXGI_FORMAT_R32_UINT;
+ default: UNREACHABLE(); return DXGI_FORMAT_UNKNOWN;
+ }
+}
+
+ID3D11Buffer *IndexBuffer11::getBuffer() const
+{
+ return mBuffer;
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/IndexBuffer11.h b/src/libGLESv2/renderer/IndexBuffer11.h
new file mode 100644
index 00000000..39a61946
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexBuffer11.h
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexBuffer11.h: Defines the D3D11 IndexBuffer implementation.
+
+#ifndef LIBGLESV2_RENDERER_INDEXBUFFER11_H_
+#define LIBGLESV2_RENDERER_INDEXBUFFER11_H_
+
+#include "libGLESv2/renderer/IndexBuffer.h"
+
+namespace rx
+{
+class Renderer11;
+
+class IndexBuffer11 : public IndexBuffer
+{
+ public:
+ explicit IndexBuffer11(Renderer11 *const renderer);
+ virtual ~IndexBuffer11();
+
+ virtual bool initialize(unsigned int bufferSize, GLenum indexType, bool dynamic);
+
+ static IndexBuffer11 *makeIndexBuffer11(IndexBuffer *indexBuffer);
+
+ virtual bool mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory);
+ virtual bool unmapBuffer();
+
+ virtual GLenum getIndexType() const;
+ virtual unsigned int getBufferSize() const;
+ virtual bool setSize(unsigned int bufferSize, GLenum indexType);
+
+ virtual bool discard();
+
+ DXGI_FORMAT getIndexFormat() const;
+ ID3D11Buffer *getBuffer() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexBuffer11);
+
+ rx::Renderer11 *const mRenderer;
+
+ ID3D11Buffer *mBuffer;
+ unsigned int mBufferSize;
+ GLenum mIndexType;
+ bool mDynamicUsage;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_INDEXBUFFER11_H_ \ No newline at end of file
diff --git a/src/libGLESv2/renderer/IndexBuffer9.cpp b/src/libGLESv2/renderer/IndexBuffer9.cpp
new file mode 100644
index 00000000..c6d83c5d
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexBuffer9.cpp
@@ -0,0 +1,207 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Indexffer9.cpp: Defines the D3D9 IndexBuffer implementation.
+
+#include "libGLESv2/renderer/IndexBuffer9.h"
+#include "libGLESv2/renderer/Renderer9.h"
+
+namespace rx
+{
+
+IndexBuffer9::IndexBuffer9(Renderer9 *const renderer) : mRenderer(renderer)
+{
+ mIndexBuffer = NULL;
+ mBufferSize = 0;
+ mIndexType = 0;
+ mDynamic = false;
+}
+
+IndexBuffer9::~IndexBuffer9()
+{
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Release();
+ mIndexBuffer = NULL;
+ }
+}
+
+bool IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic)
+{
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Release();
+ mIndexBuffer = NULL;
+ }
+
+ updateSerial();
+
+ if (bufferSize > 0)
+ {
+ D3DFORMAT format;
+ if (indexType == GL_UNSIGNED_SHORT || indexType == GL_UNSIGNED_BYTE)
+ {
+ format = D3DFMT_INDEX16;
+ }
+ else if (indexType == GL_UNSIGNED_INT)
+ {
+ if (mRenderer->get32BitIndexSupport())
+ {
+ format = D3DFMT_INDEX32;
+ }
+ else
+ {
+ ERR("Attempted to create a 32-bit index buffer but renderer does not support 32-bit indices.");
+ return false;
+ }
+ }
+ else
+ {
+ ERR("Invalid index type %u.", indexType);
+ return false;
+ }
+
+ DWORD usageFlags = D3DUSAGE_WRITEONLY;
+ if (dynamic)
+ {
+ usageFlags |= D3DUSAGE_DYNAMIC;
+ }
+
+ HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer);
+ if (FAILED(result))
+ {
+ ERR("Failed to create an index buffer of size %u, result: 0x%08x.", mBufferSize, result);
+ return false;
+ }
+ }
+
+ mBufferSize = bufferSize;
+ mIndexType = indexType;
+ mDynamic = dynamic;
+
+ return true;
+}
+
+IndexBuffer9 *IndexBuffer9::makeIndexBuffer9(IndexBuffer *indexBuffer)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer9*, indexBuffer));
+ return static_cast<IndexBuffer9*>(indexBuffer);
+}
+
+bool IndexBuffer9::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory)
+{
+ if (mIndexBuffer)
+ {
+ DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0;
+
+ void *mapPtr = NULL;
+ HRESULT result = mIndexBuffer->Lock(offset, size, &mapPtr, lockFlags);
+ if (FAILED(result))
+ {
+ ERR("Index buffer lock failed with error 0x%08x", result);
+ return false;
+ }
+
+ *outMappedMemory = mapPtr;
+ return true;
+ }
+ else
+ {
+ ERR("Index buffer not initialized.");
+ return false;
+ }
+}
+
+bool IndexBuffer9::unmapBuffer()
+{
+ if (mIndexBuffer)
+ {
+ HRESULT result = mIndexBuffer->Unlock();
+ if (FAILED(result))
+ {
+ ERR("Index buffer unlock failed with error 0x%08x", result);
+ return false;
+ }
+
+ return true;
+ }
+ else
+ {
+ ERR("Index buffer not initialized.");
+ return false;
+ }
+}
+
+GLenum IndexBuffer9::getIndexType() const
+{
+ return mIndexType;
+}
+
+unsigned int IndexBuffer9::getBufferSize() const
+{
+ return mBufferSize;
+}
+
+bool IndexBuffer9::setSize(unsigned int bufferSize, GLenum indexType)
+{
+ if (bufferSize > mBufferSize || indexType != mIndexType)
+ {
+ return initialize(bufferSize, indexType, mDynamic);
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool IndexBuffer9::discard()
+{
+ if (mIndexBuffer)
+ {
+ void *dummy;
+ HRESULT result;
+
+ result = mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ if (FAILED(result))
+ {
+ ERR("Discard lock failed with error 0x%08x", result);
+ return false;
+ }
+
+ result = mIndexBuffer->Unlock();
+ if (FAILED(result))
+ {
+ ERR("Discard unlock failed with error 0x%08x", result);
+ return false;
+ }
+
+ return true;
+ }
+ else
+ {
+ ERR("Index buffer not initialized.");
+ return false;
+ }
+}
+
+D3DFORMAT IndexBuffer9::getIndexFormat() const
+{
+ switch (mIndexType)
+ {
+ case GL_UNSIGNED_BYTE: return D3DFMT_INDEX16;
+ case GL_UNSIGNED_SHORT: return D3DFMT_INDEX16;
+ case GL_UNSIGNED_INT: return D3DFMT_INDEX32;
+ default: UNREACHABLE(); return D3DFMT_UNKNOWN;
+ }
+}
+
+IDirect3DIndexBuffer9 * IndexBuffer9::getBuffer() const
+{
+ return mIndexBuffer;
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/IndexBuffer9.h b/src/libGLESv2/renderer/IndexBuffer9.h
new file mode 100644
index 00000000..68018675
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexBuffer9.h
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Indexffer9.h: Defines the D3D9 IndexBuffer implementation.
+
+#ifndef LIBGLESV2_RENDERER_INDEXBUFFER9_H_
+#define LIBGLESV2_RENDERER_INDEXBUFFER9_H_
+
+#include "libGLESv2/renderer/IndexBuffer.h"
+
+namespace rx
+{
+class Renderer9;
+
+class IndexBuffer9 : public IndexBuffer
+{
+ public:
+ explicit IndexBuffer9(Renderer9 *const renderer);
+ virtual ~IndexBuffer9();
+
+ virtual bool initialize(unsigned int bufferSize, GLenum indexType, bool dynamic);
+
+ static IndexBuffer9 *makeIndexBuffer9(IndexBuffer *indexBuffer);
+
+ virtual bool mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory);
+ virtual bool unmapBuffer();
+
+ virtual GLenum getIndexType() const;
+ virtual unsigned int getBufferSize() const;
+ virtual bool setSize(unsigned int bufferSize, GLenum indexType);
+
+ virtual bool discard();
+
+ D3DFORMAT getIndexFormat() const;
+ IDirect3DIndexBuffer9 *getBuffer() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexBuffer9);
+
+ rx::Renderer9 *const mRenderer;
+
+ IDirect3DIndexBuffer9 *mIndexBuffer;
+ unsigned int mBufferSize;
+ GLenum mIndexType;
+ bool mDynamic;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_INDEXBUFFER9_H_
diff --git a/src/libGLESv2/renderer/IndexDataManager.cpp b/src/libGLESv2/renderer/IndexDataManager.cpp
new file mode 100644
index 00000000..752d1fb4
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexDataManager.cpp
@@ -0,0 +1,314 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// IndexDataManager.cpp: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#include "libGLESv2/renderer/IndexDataManager.h"
+#include "libGLESv2/renderer/BufferStorage.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/main.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/renderer/IndexBuffer.h"
+
+namespace rx
+{
+
+IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
+{
+ mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
+ if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
+ {
+ delete mStreamingBufferShort;
+ mStreamingBufferShort = NULL;
+ }
+
+ mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
+ if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
+ {
+ delete mStreamingBufferInt;
+ mStreamingBufferInt = NULL;
+ }
+
+ if (!mStreamingBufferShort)
+ {
+ // Make sure both buffers are deleted.
+ delete mStreamingBufferInt;
+ mStreamingBufferInt = NULL;
+
+ ERR("Failed to allocate the streaming index buffer(s).");
+ }
+
+ mCountingBuffer = NULL;
+}
+
+IndexDataManager::~IndexDataManager()
+{
+ delete mStreamingBufferShort;
+ delete mStreamingBufferInt;
+ delete mCountingBuffer;
+}
+
+static void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
+{
+ if (type == GL_UNSIGNED_BYTE)
+ {
+ const GLubyte *in = static_cast<const GLubyte*>(input);
+ GLushort *out = static_cast<GLushort*>(output);
+
+ for (GLsizei i = 0; i < count; i++)
+ {
+ out[i] = in[i];
+ }
+ }
+ else if (type == GL_UNSIGNED_INT)
+ {
+ memcpy(output, input, count * sizeof(GLuint));
+ }
+ else if (type == GL_UNSIGNED_SHORT)
+ {
+ memcpy(output, input, count * sizeof(GLushort));
+ }
+ else UNREACHABLE();
+}
+
+template <class IndexType>
+static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+{
+ *minIndex = indices[0];
+ *maxIndex = indices[0];
+
+ for (GLsizei i = 0; i < count; i++)
+ {
+ if (*minIndex > indices[i]) *minIndex = indices[i];
+ if (*maxIndex < indices[i]) *maxIndex = indices[i];
+ }
+}
+
+static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+{
+ if (type == GL_UNSIGNED_BYTE)
+ {
+ computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
+ }
+ else if (type == GL_UNSIGNED_INT)
+ {
+ computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
+ }
+ else if (type == GL_UNSIGNED_SHORT)
+ {
+ computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
+ }
+ else UNREACHABLE();
+}
+
+GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
+{
+ if (!mStreamingBufferShort)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ bool alignedOffset = false;
+
+ BufferStorage *storage = NULL;
+
+ if (buffer != NULL)
+ {
+ storage = buffer->getStorage();
+
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
+ case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
+ case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
+ default: UNREACHABLE(); alignedOffset = false;
+ }
+
+ if (gl::ComputeTypeSize(type) * count + offset > static_cast<GLsizei>(storage->getSize()))
+ {
+ return GL_INVALID_OPERATION;
+ }
+
+ indices = static_cast<const GLubyte*>(storage->getData()) + offset;
+ }
+
+ StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
+
+ StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
+ IndexBufferInterface *indexBuffer = streamingBuffer;
+ bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
+ destinationIndexType == type;
+ UINT streamOffset = 0;
+
+ if (directStorage)
+ {
+ indexBuffer = streamingBuffer;
+ streamOffset = offset;
+ storage->markBufferUsage();
+
+ if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
+ &translated->maxIndex, NULL))
+ {
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+ buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
+ translated->maxIndex, offset);
+ }
+ }
+ else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
+ {
+ indexBuffer = staticBuffer;
+ if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
+ &translated->maxIndex, &streamOffset))
+ {
+ streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+ staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
+ translated->maxIndex, streamOffset);
+ }
+ }
+ else
+ {
+ int convertCount = count;
+
+ if (staticBuffer)
+ {
+ if (staticBuffer->getBufferSize() == 0 && alignedOffset)
+ {
+ indexBuffer = staticBuffer;
+ convertCount = storage->getSize() / gl::ComputeTypeSize(type);
+ }
+ else
+ {
+ buffer->invalidateStaticData();
+ staticBuffer = NULL;
+ }
+ }
+
+ if (!indexBuffer)
+ {
+ ERR("No valid index buffer.");
+ return GL_INVALID_OPERATION;
+ }
+
+ unsigned int bufferSizeRequired = convertCount * gl::ComputeTypeSize(destinationIndexType);
+ indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
+
+ void* output = NULL;
+ streamOffset = indexBuffer->mapBuffer(bufferSizeRequired, &output);
+ if (streamOffset == -1 || output == NULL)
+ {
+ ERR("Failed to map index buffer.");
+ return GL_OUT_OF_MEMORY;
+ }
+
+ convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
+
+ if (!indexBuffer->unmapBuffer())
+ {
+ ERR("Failed to unmap index buffer.");
+ return GL_OUT_OF_MEMORY;
+ }
+
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+
+ if (staticBuffer)
+ {
+ streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
+ staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
+ translated->maxIndex, streamOffset);
+ }
+ }
+
+ translated->storage = directStorage ? storage : NULL;
+ translated->indexBuffer = indexBuffer->getIndexBuffer();
+ translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
+ translated->startIndex = streamOffset / gl::ComputeTypeSize(destinationIndexType);
+ translated->startOffset = streamOffset;
+
+ if (buffer)
+ {
+ buffer->promoteStaticUsage(count * gl::ComputeTypeSize(type));
+ }
+
+ return GL_NO_ERROR;
+}
+
+StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
+{
+ if (count <= 65536) // 16-bit indices
+ {
+ const unsigned int spaceNeeded = count * sizeof(unsigned short);
+
+ if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
+ {
+ delete mCountingBuffer;
+ mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
+ mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
+
+ void* mappedMemory = NULL;
+ if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
+ {
+ ERR("Failed to map counting buffer.");
+ return NULL;
+ }
+
+ unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
+ for(int i = 0; i < count; i++)
+ {
+ data[i] = i;
+ }
+
+ if (!mCountingBuffer->unmapBuffer())
+ {
+ ERR("Failed to unmap counting buffer.");
+ return NULL;
+ }
+ }
+ }
+ else if (mStreamingBufferInt) // 32-bit indices supported
+ {
+ const unsigned int spaceNeeded = count * sizeof(unsigned int);
+
+ if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
+ {
+ delete mCountingBuffer;
+ mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
+ mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
+
+ void* mappedMemory = NULL;
+ if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
+ {
+ ERR("Failed to map counting buffer.");
+ return NULL;
+ }
+
+ unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
+ for(int i = 0; i < count; i++)
+ {
+ data[i] = i;
+ }
+
+ if (!mCountingBuffer->unmapBuffer())
+ {
+ ERR("Failed to unmap counting buffer.");
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ return NULL;
+ }
+
+ return mCountingBuffer;
+}
+
+}
diff --git a/src/libGLESv2/renderer/IndexDataManager.h b/src/libGLESv2/renderer/IndexDataManager.h
new file mode 100644
index 00000000..0e77c81d
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexDataManager.h
@@ -0,0 +1,66 @@
+//
+// 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.
+//
+
+// IndexDataManager.h: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#ifndef LIBGLESV2_INDEXDATAMANAGER_H_
+#define LIBGLESV2_INDEXDATAMANAGER_H_
+
+#include "common/angleutils.h"
+
+namespace
+{
+ enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
+}
+
+namespace gl
+{
+class Buffer;
+}
+
+namespace rx
+{
+class StaticIndexBufferInterface;
+class StreamingIndexBufferInterface;
+class IndexBuffer;
+class BufferStorage;
+class Renderer;
+
+struct TranslatedIndexData
+{
+ unsigned int minIndex;
+ unsigned int maxIndex;
+ unsigned int startIndex;
+ unsigned int startOffset; // In bytes
+
+ IndexBuffer *indexBuffer;
+ BufferStorage *storage;
+ unsigned int serial;
+};
+
+class IndexDataManager
+{
+ public:
+ explicit IndexDataManager(Renderer *renderer);
+ virtual ~IndexDataManager();
+
+ GLenum prepareIndexData(GLenum type, GLsizei count, gl::Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated);
+ StaticIndexBufferInterface *getCountingIndices(GLsizei count);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexDataManager);
+
+ Renderer *const mRenderer;
+
+ StreamingIndexBufferInterface *mStreamingBufferShort;
+ StreamingIndexBufferInterface *mStreamingBufferInt;
+ StaticIndexBufferInterface *mCountingBuffer;
+};
+
+}
+
+#endif // LIBGLESV2_INDEXDATAMANAGER_H_
diff --git a/src/libGLESv2/renderer/IndexRangeCache.cpp b/src/libGLESv2/renderer/IndexRangeCache.cpp
new file mode 100644
index 00000000..7630934a
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexRangeCache.cpp
@@ -0,0 +1,97 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexRangeCache.cpp: Defines the rx::IndexRangeCache class which stores information about
+// ranges of indices.
+
+#include "libGLESv2/renderer/IndexRangeCache.h"
+#include "common/debug.h"
+#include "libGLESv2/utilities.h"
+#include <tuple>
+
+namespace rx
+{
+
+void IndexRangeCache::addRange(GLenum type, intptr_t offset, GLsizei count, unsigned int minIdx, unsigned int maxIdx,
+ unsigned int streamOffset)
+{
+ mIndexRangeCache[IndexRange(type, offset, count)] = IndexBounds(minIdx, maxIdx, streamOffset);
+}
+
+void IndexRangeCache::invalidateRange(unsigned int offset, unsigned int size)
+{
+ unsigned int invalidateStart = offset;
+ unsigned int invalidateEnd = offset + size;
+
+ IndexRangeMap::iterator i = mIndexRangeCache.begin();
+ while (i != mIndexRangeCache.end())
+ {
+ unsigned int rangeStart = i->second.streamOffset;
+ unsigned int rangeEnd = i->second.streamOffset + (gl::ComputeTypeSize(i->first.type) * i->first.count);
+
+ if (invalidateEnd < rangeStart || invalidateStart > rangeEnd)
+ {
+ ++i;
+ }
+ else
+ {
+ i = mIndexRangeCache.erase(i);
+ }
+ }
+}
+
+bool IndexRangeCache::findRange(GLenum type, intptr_t offset, GLsizei count, unsigned int *outMinIndex,
+ unsigned int *outMaxIndex, unsigned int *outStreamOffset) const
+{
+ IndexRangeMap::const_iterator i = mIndexRangeCache.find(IndexRange(type, offset, count));
+ if (i != mIndexRangeCache.end())
+ {
+ if (outMinIndex) *outMinIndex = i->second.minIndex;
+ if (outMaxIndex) *outMaxIndex = i->second.maxIndex;
+ if (outStreamOffset) *outStreamOffset = i->second.streamOffset;
+ return true;
+ }
+ else
+ {
+ if (outMinIndex) *outMinIndex = 0;
+ if (outMaxIndex) *outMaxIndex = 0;
+ if (outStreamOffset) *outStreamOffset = 0;
+ return false;
+ }
+}
+
+void IndexRangeCache::clear()
+{
+ mIndexRangeCache.clear();
+}
+
+IndexRangeCache::IndexRange::IndexRange()
+ : type(GL_NONE), offset(0), count(0)
+{
+}
+
+IndexRangeCache::IndexRange::IndexRange(GLenum typ, intptr_t off, GLsizei c)
+ : type(typ), offset(off), count(c)
+{
+}
+
+bool IndexRangeCache::IndexRange::operator<(const IndexRange& rhs) const
+{
+ return std::make_tuple(type, offset, count) < std::make_tuple(rhs.type, rhs.offset, rhs.count);
+}
+
+IndexRangeCache::IndexBounds::IndexBounds()
+ : minIndex(0), maxIndex(0), streamOffset(0)
+{
+}
+
+IndexRangeCache::IndexBounds::IndexBounds(unsigned int minIdx, unsigned int maxIdx, unsigned int offset)
+ : minIndex(minIdx), maxIndex(maxIdx), streamOffset(offset)
+{
+}
+
+}
diff --git a/src/libGLESv2/renderer/IndexRangeCache.h b/src/libGLESv2/renderer/IndexRangeCache.h
new file mode 100644
index 00000000..5a5ade10
--- /dev/null
+++ b/src/libGLESv2/renderer/IndexRangeCache.h
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexRangeCache.h: Defines the rx::IndexRangeCache class which stores information about
+// ranges of indices.
+
+#ifndef LIBGLESV2_RENDERER_INDEXRANGECACHE_H_
+#define LIBGLESV2_RENDERER_INDEXRANGECACHE_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+
+class IndexRangeCache
+{
+ public:
+ void addRange(GLenum type, intptr_t offset, GLsizei count, unsigned int minIdx, unsigned int maxIdx,
+ unsigned int streamOffset);
+ bool findRange(GLenum type, intptr_t offset, GLsizei count, unsigned int *outMinIndex,
+ unsigned int *outMaxIndex, unsigned int *outStreamOffset) const;
+
+ void invalidateRange(unsigned int offset, unsigned int size);
+ void clear();
+
+ private:
+ struct IndexRange
+ {
+ GLenum type;
+ intptr_t offset;
+ GLsizei count;
+
+ IndexRange();
+ IndexRange(GLenum type, intptr_t offset, GLsizei count);
+
+ bool operator<(const IndexRange& rhs) const;
+ };
+
+ struct IndexBounds
+ {
+ unsigned int minIndex;
+ unsigned int maxIndex;
+ unsigned int streamOffset;
+
+ IndexBounds();
+ IndexBounds(unsigned int minIdx, unsigned int maxIdx, unsigned int offset);
+ };
+
+ typedef std::map<IndexRange, IndexBounds> IndexRangeMap;
+ IndexRangeMap mIndexRangeCache;
+};
+
+}
+
+#endif LIBGLESV2_RENDERER_INDEXRANGECACHE_H
diff --git a/src/libGLESv2/renderer/InputLayoutCache.cpp b/src/libGLESv2/renderer/InputLayoutCache.cpp
new file mode 100644
index 00000000..fcc6f7ce
--- /dev/null
+++ b/src/libGLESv2/renderer/InputLayoutCache.cpp
@@ -0,0 +1,202 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches
+// D3D11 input layouts.
+
+#include "libGLESv2/renderer/InputLayoutCache.h"
+#include "libGLESv2/renderer/VertexBuffer11.h"
+#include "libGLESv2/renderer/BufferStorage11.h"
+#include "libGLESv2/renderer/ShaderExecutable11.h"
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/renderer/VertexDataManager.h"
+
+#include "third_party/murmurhash/MurmurHash3.h"
+
+namespace rx
+{
+
+const unsigned int InputLayoutCache::kMaxInputLayouts = 1024;
+
+InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts)
+{
+ mCounter = 0;
+ mDevice = NULL;
+ mDeviceContext = NULL;
+ mCurrentIL = NULL;
+ for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mCurrentBuffers[i] = -1;
+ mCurrentVertexStrides[i] = -1;
+ mCurrentVertexOffsets[i] = -1;
+ }
+}
+
+InputLayoutCache::~InputLayoutCache()
+{
+ clear();
+}
+
+void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context)
+{
+ clear();
+ mDevice = device;
+ mDeviceContext = context;
+}
+
+void InputLayoutCache::clear()
+{
+ for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
+ {
+ i->second.inputLayout->Release();
+ }
+ mInputLayoutMap.clear();
+ markDirty();
+}
+
+void InputLayoutCache::markDirty()
+{
+ mCurrentIL = NULL;
+ for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mCurrentBuffers[i] = -1;
+ mCurrentVertexStrides[i] = -1;
+ mCurrentVertexOffsets[i] = -1;
+ }
+}
+
+GLenum InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
+ gl::ProgramBinary *programBinary)
+{
+ int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
+ programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices);
+
+ if (!mDevice || !mDeviceContext)
+ {
+ ERR("InputLayoutCache is not initialized.");
+ return GL_INVALID_OPERATION;
+ }
+
+ InputLayoutKey ilKey = { 0 };
+
+ ID3D11Buffer *vertexBuffers[gl::MAX_VERTEX_ATTRIBS] = { NULL };
+ unsigned int vertexBufferSerials[gl::MAX_VERTEX_ATTRIBS] = { 0 };
+ UINT vertexStrides[gl::MAX_VERTEX_ATTRIBS] = { 0 };
+ UINT vertexOffsets[gl::MAX_VERTEX_ATTRIBS] = { 0 };
+
+ static const char* semanticName = "TEXCOORD";
+
+ for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (attributes[i].active)
+ {
+ VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer);
+ BufferStorage11 *bufferStorage = attributes[i].storage ? BufferStorage11::makeBufferStorage11(attributes[i].storage) : NULL;
+
+ D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
+
+ // Record the type of the associated vertex shader vector in our key
+ // This will prevent mismatched vertex shaders from using the same input layout
+ GLint attributeSize;
+ programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.glslElementType[ilKey.elementCount], NULL);
+
+ ilKey.elements[ilKey.elementCount].SemanticName = semanticName;
+ ilKey.elements[ilKey.elementCount].SemanticIndex = sortedSemanticIndices[i];
+ ilKey.elements[ilKey.elementCount].Format = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDXGIFormat(*attributes[i].attribute) : DXGI_FORMAT_R32G32B32A32_FLOAT;
+ ilKey.elements[ilKey.elementCount].InputSlot = i;
+ ilKey.elements[ilKey.elementCount].AlignedByteOffset = 0;
+ ilKey.elements[ilKey.elementCount].InputSlotClass = inputClass;
+ ilKey.elements[ilKey.elementCount].InstanceDataStepRate = attributes[i].divisor;
+ ilKey.elementCount++;
+
+ vertexBuffers[i] = bufferStorage ? bufferStorage->getBuffer() : vertexBuffer->getBuffer();
+ vertexBufferSerials[i] = bufferStorage ? bufferStorage->getSerial() : vertexBuffer->getSerial();
+ vertexStrides[i] = attributes[i].stride;
+ vertexOffsets[i] = attributes[i].offset;
+ }
+ }
+
+ ID3D11InputLayout *inputLayout = NULL;
+
+ InputLayoutMap::iterator i = mInputLayoutMap.find(ilKey);
+ if (i != mInputLayoutMap.end())
+ {
+ inputLayout = i->second.inputLayout;
+ i->second.lastUsedTime = mCounter++;
+ }
+ else
+ {
+ ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutable());
+
+ HRESULT result = mDevice->CreateInputLayout(ilKey.elements, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout);
+ if (FAILED(result))
+ {
+ ERR("Failed to crate input layout, result: 0x%08x", result);
+ return GL_INVALID_OPERATION;
+ }
+
+ if (mInputLayoutMap.size() >= kMaxInputLayouts)
+ {
+ TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
+ "to make room.", kMaxInputLayouts);
+
+ InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin();
+ for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++)
+ {
+ if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime)
+ {
+ leastRecentlyUsed = i;
+ }
+ }
+ leastRecentlyUsed->second.inputLayout->Release();
+ mInputLayoutMap.erase(leastRecentlyUsed);
+ }
+
+ InputLayoutCounterPair inputCounterPair;
+ inputCounterPair.inputLayout = inputLayout;
+ inputCounterPair.lastUsedTime = mCounter++;
+
+ mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair));
+ }
+
+ if (inputLayout != mCurrentIL)
+ {
+ mDeviceContext->IASetInputLayout(inputLayout);
+ mCurrentIL = inputLayout;
+ }
+
+ for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (vertexBufferSerials[i] != mCurrentBuffers[i] || vertexStrides[i] != mCurrentVertexStrides[i] ||
+ vertexOffsets[i] != mCurrentVertexOffsets[i])
+ {
+ mDeviceContext->IASetVertexBuffers(i, 1, &vertexBuffers[i], &vertexStrides[i], &vertexOffsets[i]);
+ mCurrentBuffers[i] = vertexBufferSerials[i];
+ mCurrentVertexStrides[i] = vertexStrides[i];
+ mCurrentVertexOffsets[i] = vertexOffsets[i];
+ }
+ }
+
+ return GL_NO_ERROR;
+}
+
+std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout)
+{
+ static const unsigned int seed = 0xDEADBEEF;
+
+ std::size_t hash = 0;
+ MurmurHash3_x86_32(&inputLayout, sizeof(InputLayoutKey), seed, &hash);
+ return hash;
+}
+
+bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b)
+{
+ return memcmp(&a, &b, sizeof(InputLayoutKey)) == 0;
+}
+
+}
diff --git a/src/libGLESv2/renderer/InputLayoutCache.h b/src/libGLESv2/renderer/InputLayoutCache.h
new file mode 100644
index 00000000..797853de
--- /dev/null
+++ b/src/libGLESv2/renderer/InputLayoutCache.h
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// InputLayoutCache.h: Defines InputLayoutCache, a class that builds and caches
+// D3D11 input layouts.
+
+#ifndef LIBGLESV2_RENDERER_INPUTLAYOUTCACHE_H_
+#define LIBGLESV2_RENDERER_INPUTLAYOUTCACHE_H_
+
+#include "libGLESv2/Constants.h"
+#include "common/angleutils.h"
+
+namespace gl
+{
+class ProgramBinary;
+}
+
+namespace rx
+{
+struct TranslatedAttribute;
+
+class InputLayoutCache
+{
+ public:
+ InputLayoutCache();
+ virtual ~InputLayoutCache();
+
+ void initialize(ID3D11Device *device, ID3D11DeviceContext *context);
+ void clear();
+ void markDirty();
+
+ GLenum applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
+ gl::ProgramBinary *programBinary);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(InputLayoutCache);
+
+ struct InputLayoutKey
+ {
+ unsigned int elementCount;
+ D3D11_INPUT_ELEMENT_DESC elements[gl::MAX_VERTEX_ATTRIBS];
+ GLenum glslElementType[gl::MAX_VERTEX_ATTRIBS];
+ };
+
+ struct InputLayoutCounterPair
+ {
+ ID3D11InputLayout *inputLayout;
+ unsigned long long lastUsedTime;
+ };
+
+ ID3D11InputLayout *mCurrentIL;
+ unsigned int mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS];
+ UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS];
+ UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS];
+
+ static std::size_t hashInputLayout(const InputLayoutKey &inputLayout);
+ static bool compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b);
+
+ typedef std::size_t (*InputLayoutHashFunction)(const InputLayoutKey &);
+ typedef bool (*InputLayoutEqualityFunction)(const InputLayoutKey &, const InputLayoutKey &);
+ typedef std::unordered_map<InputLayoutKey,
+ InputLayoutCounterPair,
+ InputLayoutHashFunction,
+ InputLayoutEqualityFunction> InputLayoutMap;
+ InputLayoutMap mInputLayoutMap;
+
+ static const unsigned int kMaxInputLayouts;
+
+ unsigned long long mCounter;
+
+ ID3D11Device *mDevice;
+ ID3D11DeviceContext *mDeviceContext;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_INPUTLAYOUTCACHE_H_
diff --git a/src/libGLESv2/renderer/Query11.cpp b/src/libGLESv2/renderer/Query11.cpp
new file mode 100644
index 00000000..13210fc9
--- /dev/null
+++ b/src/libGLESv2/renderer/Query11.cpp
@@ -0,0 +1,122 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl.
+
+#include "libGLESv2/renderer/Query11.h"
+#include "libGLESv2/renderer/Renderer11.h"
+#include "libGLESv2/main.h"
+
+namespace rx
+{
+
+Query11::Query11(rx::Renderer11 *renderer, GLenum type) : QueryImpl(type)
+{
+ mRenderer = renderer;
+ mQuery = NULL;
+}
+
+Query11::~Query11()
+{
+ if (mQuery)
+ {
+ mQuery->Release();
+ mQuery = NULL;
+ }
+}
+
+void Query11::begin()
+{
+ if (mQuery == NULL)
+ {
+ D3D11_QUERY_DESC queryDesc;
+ queryDesc.Query = D3D11_QUERY_OCCLUSION;
+ queryDesc.MiscFlags = 0;
+
+ if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery)))
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ mRenderer->getDeviceContext()->Begin(mQuery);
+}
+
+void Query11::end()
+{
+ if (mQuery == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ mRenderer->getDeviceContext()->End(mQuery);
+
+ mStatus = GL_FALSE;
+ mResult = GL_FALSE;
+}
+
+GLuint Query11::getResult()
+{
+ if (mQuery != NULL)
+ {
+ while (!testQuery())
+ {
+ Sleep(0);
+ // explicitly check for device loss, some drivers seem to return S_FALSE
+ // if the device is lost
+ if (mRenderer->testDeviceLost(true))
+ {
+ return gl::error(GL_OUT_OF_MEMORY, 0);
+ }
+ }
+ }
+
+ return mResult;
+}
+
+GLboolean Query11::isResultAvailable()
+{
+ if (mQuery != NULL)
+ {
+ testQuery();
+ }
+
+ return mStatus;
+}
+
+GLboolean Query11::testQuery()
+{
+ if (mQuery != NULL && mStatus != GL_TRUE)
+ {
+ UINT64 numPixels = 0;
+ HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, &numPixels, sizeof(UINT64), 0);
+ if (result == S_OK)
+ {
+ mStatus = GL_TRUE;
+
+ switch (getType())
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else if (mRenderer->testDeviceLost(true))
+ {
+ return gl::error(GL_OUT_OF_MEMORY, GL_TRUE);
+ }
+
+ return mStatus;
+ }
+
+ return GL_TRUE; // prevent blocking when query is null
+}
+
+}
diff --git a/src/libGLESv2/renderer/Query11.h b/src/libGLESv2/renderer/Query11.h
new file mode 100644
index 00000000..0a03de77
--- /dev/null
+++ b/src/libGLESv2/renderer/Query11.h
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Query11.h: Defines the rx::Query11 class which implements rx::QueryImpl.
+
+#ifndef LIBGLESV2_RENDERER_QUERY11_H_
+#define LIBGLESV2_RENDERER_QUERY11_H_
+
+#include "libGLESv2/renderer/QueryImpl.h"
+
+namespace rx
+{
+class Renderer11;
+
+class Query11 : public QueryImpl
+{
+ public:
+ Query11(rx::Renderer11 *renderer, GLenum type);
+ virtual ~Query11();
+
+ void begin();
+ void end();
+ GLuint getResult();
+ GLboolean isResultAvailable();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Query11);
+
+ GLboolean testQuery();
+
+ rx::Renderer11 *mRenderer;
+ ID3D11Query *mQuery;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_QUERY11_H_
diff --git a/src/libGLESv2/renderer/Query9.cpp b/src/libGLESv2/renderer/Query9.cpp
new file mode 100644
index 00000000..ef694267
--- /dev/null
+++ b/src/libGLESv2/renderer/Query9.cpp
@@ -0,0 +1,125 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Query9.cpp: Defines the rx::Query9 class which implements rx::QueryImpl.
+
+
+#include "libGLESv2/renderer/Query9.h"
+#include "libGLESv2/main.h"
+#include "libGLESv2/renderer/renderer9_utils.h"
+#include "libGLESv2/renderer/Renderer9.h"
+
+namespace rx
+{
+
+Query9::Query9(rx::Renderer9 *renderer, GLenum type) : QueryImpl(type)
+{
+ mRenderer = renderer;
+ mQuery = NULL;
+}
+
+Query9::~Query9()
+{
+ if (mQuery)
+ {
+ mQuery->Release();
+ mQuery = NULL;
+ }
+}
+
+void Query9::begin()
+{
+ if (mQuery == NULL)
+ {
+ if (FAILED(mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery)))
+ {
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ HRESULT result = mQuery->Issue(D3DISSUE_BEGIN);
+ ASSERT(SUCCEEDED(result));
+}
+
+void Query9::end()
+{
+ if (mQuery == NULL)
+ {
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ HRESULT result = mQuery->Issue(D3DISSUE_END);
+ ASSERT(SUCCEEDED(result));
+
+ mStatus = GL_FALSE;
+ mResult = GL_FALSE;
+}
+
+GLuint Query9::getResult()
+{
+ if (mQuery != NULL)
+ {
+ while (!testQuery())
+ {
+ Sleep(0);
+ // explicitly check for device loss
+ // some drivers seem to return S_FALSE even if the device is lost
+ // instead of D3DERR_DEVICELOST like they should
+ if (mRenderer->testDeviceLost(true))
+ {
+ return gl::error(GL_OUT_OF_MEMORY, 0);
+ }
+ }
+ }
+
+ return mResult;
+}
+
+GLboolean Query9::isResultAvailable()
+{
+ if (mQuery != NULL)
+ {
+ testQuery();
+ }
+
+ return mStatus;
+}
+
+GLboolean Query9::testQuery()
+{
+ if (mQuery != NULL && mStatus != GL_TRUE)
+ {
+ DWORD numPixels = 0;
+
+ HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH);
+ if (hres == S_OK)
+ {
+ mStatus = GL_TRUE;
+
+ switch (getType())
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE;
+ break;
+ default:
+ ASSERT(false);
+ }
+ }
+ else if (d3d9::isDeviceLostError(hres))
+ {
+ mRenderer->notifyDeviceLost();
+ return gl::error(GL_OUT_OF_MEMORY, GL_TRUE);
+ }
+
+ return mStatus;
+ }
+
+ return GL_TRUE; // prevent blocking when query is null
+}
+
+}
diff --git a/src/libGLESv2/renderer/Query9.h b/src/libGLESv2/renderer/Query9.h
new file mode 100644
index 00000000..47eef893
--- /dev/null
+++ b/src/libGLESv2/renderer/Query9.h
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Query9.h: Defines the rx::Query9 class which implements rx::QueryImpl.
+
+#ifndef LIBGLESV2_RENDERER_QUERY9_H_
+#define LIBGLESV2_RENDERER_QUERY9_H_
+
+#include "libGLESv2/renderer/QueryImpl.h"
+
+namespace rx
+{
+class Renderer9;
+
+class Query9 : public QueryImpl
+{
+ public:
+ Query9(rx::Renderer9 *renderer, GLenum type);
+ virtual ~Query9();
+
+ void begin();
+ void end();
+ GLuint getResult();
+ GLboolean isResultAvailable();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Query9);
+
+ GLboolean testQuery();
+
+ rx::Renderer9 *mRenderer;
+ IDirect3DQuery9 *mQuery;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_QUERY9_H_
diff --git a/src/libGLESv2/renderer/QueryImpl.h b/src/libGLESv2/renderer/QueryImpl.h
new file mode 100644
index 00000000..a874047b
--- /dev/null
+++ b/src/libGLESv2/renderer/QueryImpl.h
@@ -0,0 +1,42 @@
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// QueryImpl.h: Defines the abstract rx::QueryImpl class.
+
+#ifndef LIBGLESV2_RENDERER_QUERYIMPL_H_
+#define LIBGLESV2_RENDERER_QUERYIMPL_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+
+class QueryImpl
+{
+ public:
+ explicit QueryImpl(GLenum type) : mType(type), mStatus(GL_FALSE), mResult(0) { }
+ virtual ~QueryImpl() { }
+
+ virtual void begin() = 0;
+ virtual void end() = 0;
+ virtual GLuint getResult() = 0;
+ virtual GLboolean isResultAvailable() = 0;
+
+ GLenum getType() const { return mType; }
+
+ protected:
+ GLuint mResult;
+ GLboolean mStatus;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QueryImpl);
+
+ GLenum mType;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_QUERYIMPL_H_
diff --git a/src/libGLESv2/renderer/RenderStateCache.cpp b/src/libGLESv2/renderer/RenderStateCache.cpp
new file mode 100644
index 00000000..b3111af7
--- /dev/null
+++ b/src/libGLESv2/renderer/RenderStateCache.cpp
@@ -0,0 +1,406 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render
+// state objects.
+
+#include "libGLESv2/renderer/RenderStateCache.h"
+#include "libGLESv2/renderer/renderer11_utils.h"
+
+#include "common/debug.h"
+#include "third_party/murmurhash/MurmurHash3.h"
+
+namespace rx
+{
+
+// 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() : mDevice(NULL), mCounter(0),
+ mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates),
+ mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates),
+ mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates),
+ mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates)
+{
+}
+
+RenderStateCache::~RenderStateCache()
+{
+ clear();
+}
+
+void RenderStateCache::initialize(ID3D11Device *device)
+{
+ clear();
+ mDevice = device;
+}
+
+void RenderStateCache::clear()
+{
+ for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++)
+ {
+ i->second.first->Release();
+ }
+ mBlendStateCache.clear();
+
+ for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++)
+ {
+ i->second.first->Release();
+ }
+ mRasterizerStateCache.clear();
+
+ for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++)
+ {
+ i->second.first->Release();
+ }
+ mDepthStencilStateCache.clear();
+
+ for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++)
+ {
+ i->second.first->Release();
+ }
+ mSamplerStateCache.clear();
+}
+
+std::size_t RenderStateCache::hashBlendState(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;
+}
+
+bool RenderStateCache::compareBlendStates(const gl::BlendState &a, const gl::BlendState &b)
+{
+ return memcmp(&a, &b, sizeof(gl::BlendState)) == 0;
+}
+
+ID3D11BlendState *RenderStateCache::getBlendState(const gl::BlendState &blendState)
+{
+ if (!mDevice)
+ {
+ ERR("RenderStateCache is not initialized.");
+ return NULL;
+ }
+
+ BlendStateMap::iterator i = mBlendStateCache.find(blendState);
+ if (i != mBlendStateCache.end())
+ {
+ BlendStateCounterPair &state = i->second;
+ state.second = mCounter++;
+ return state.first;
+ }
+ 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;
+ }
+ }
+ leastRecentlyUsed->second.first->Release();
+ 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 = FALSE;
+
+ for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
+ {
+ D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = blendDesc.RenderTarget[i];
+
+ rtBlend.BlendEnable = blendState.blend;
+ if (blendState.blend)
+ {
+ rtBlend.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false);
+ rtBlend.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false);
+ rtBlend.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB);
+
+ rtBlend.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true);
+ rtBlend.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true);
+ rtBlend.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha);
+ }
+
+ rtBlend.RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendState.colorMaskRed,
+ blendState.colorMaskGreen,
+ blendState.colorMaskBlue,
+ blendState.colorMaskAlpha);
+ }
+
+ ID3D11BlendState *dx11BlendState = NULL;
+ HRESULT result = mDevice->CreateBlendState(&blendDesc, &dx11BlendState);
+ if (FAILED(result) || !dx11BlendState)
+ {
+ ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result);
+ return NULL;
+ }
+
+ mBlendStateCache.insert(std::make_pair(blendState, std::make_pair(dx11BlendState, mCounter++)));
+
+ return dx11BlendState;
+ }
+}
+
+std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState)
+{
+ static const unsigned int seed = 0xABCDEF98;
+
+ std::size_t hash = 0;
+ MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash);
+ return hash;
+}
+
+bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b)
+{
+ return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0;
+}
+
+ID3D11RasterizerState *RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState,
+ bool scissorEnabled, unsigned int depthSize)
+{
+ if (!mDevice)
+ {
+ ERR("RenderStateCache is not initialized.");
+ return NULL;
+ }
+
+ RasterizerStateKey key;
+ key.rasterizerState = rasterState;
+ key.scissorEnabled = scissorEnabled;
+ key.depthSize = depthSize;
+
+ RasterizerStateMap::iterator i = mRasterizerStateCache.find(key);
+ if (i != mRasterizerStateCache.end())
+ {
+ RasterizerStateCounterPair &state = i->second;
+ state.second = mCounter++;
+ return state.first;
+ }
+ 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;
+ }
+ }
+ leastRecentlyUsed->second.first->Release();
+ mRasterizerStateCache.erase(leastRecentlyUsed);
+ }
+
+ D3D11_CULL_MODE cullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode);
+
+ // Disable culling if drawing points
+ if (rasterState.pointDrawMode)
+ {
+ cullMode = D3D11_CULL_NONE;
+ }
+
+ D3D11_RASTERIZER_DESC rasterDesc;
+ rasterDesc.FillMode = D3D11_FILL_SOLID;
+ rasterDesc.CullMode = cullMode;
+ rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE: TRUE;
+ rasterDesc.DepthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(depthSize));
+ rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though.
+ rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor;
+ rasterDesc.DepthClipEnable = TRUE;
+ rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE;
+ rasterDesc.MultisampleEnable = rasterState.multiSample;
+ rasterDesc.AntialiasedLineEnable = FALSE;
+
+ ID3D11RasterizerState *dx11RasterizerState = NULL;
+ HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState);
+ if (FAILED(result) || !dx11RasterizerState)
+ {
+ ERR("Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result);
+ return NULL;
+ }
+
+ mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++)));
+
+ return dx11RasterizerState;
+ }
+}
+
+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;
+}
+
+ID3D11DepthStencilState *RenderStateCache::getDepthStencilState(const gl::DepthStencilState &dsState)
+{
+ if (!mDevice)
+ {
+ ERR("RenderStateCache is not initialized.");
+ return NULL;
+ }
+
+ DepthStencilStateMap::iterator i = mDepthStencilStateCache.find(dsState);
+ if (i != mDepthStencilStateCache.end())
+ {
+ DepthStencilStateCounterPair &state = i->second;
+ state.second = mCounter++;
+ return state.first;
+ }
+ else
+ {
+ if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates)
+ {
+ TRACE("Overflowed the limit of %u depth stencil states, removing the least recently used "
+ "to make room.", kMaxDepthStencilStates);
+
+ DepthStencilStateMap::iterator leastRecentlyUsed = mDepthStencilStateCache.begin();
+ for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++)
+ {
+ if (i->second.second < leastRecentlyUsed->second.second)
+ {
+ leastRecentlyUsed = i;
+ }
+ }
+ leastRecentlyUsed->second.first->Release();
+ mDepthStencilStateCache.erase(leastRecentlyUsed);
+ }
+
+ D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 };
+ dsDesc.DepthEnable = dsState.depthTest ? TRUE : FALSE;
+ dsDesc.DepthWriteMask = gl_d3d11::ConvertDepthMask(dsState.depthMask);
+ dsDesc.DepthFunc = gl_d3d11::ConvertComparison(dsState.depthFunc);
+ dsDesc.StencilEnable = dsState.stencilTest ? TRUE : FALSE;
+ dsDesc.StencilReadMask = gl_d3d11::ConvertStencilMask(dsState.stencilMask);
+ dsDesc.StencilWriteMask = gl_d3d11::ConvertStencilMask(dsState.stencilWritemask);
+ dsDesc.FrontFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilFail);
+ dsDesc.FrontFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthFail);
+ dsDesc.FrontFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthPass);
+ dsDesc.FrontFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilFunc);
+ dsDesc.BackFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackFail);
+ dsDesc.BackFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthFail);
+ dsDesc.BackFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthPass);
+ dsDesc.BackFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilBackFunc);
+
+ ID3D11DepthStencilState *dx11DepthStencilState = NULL;
+ HRESULT result = mDevice->CreateDepthStencilState(&dsDesc, &dx11DepthStencilState);
+ if (FAILED(result) || !dx11DepthStencilState)
+ {
+ ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result);
+ return NULL;
+ }
+
+ mDepthStencilStateCache.insert(std::make_pair(dsState, std::make_pair(dx11DepthStencilState, mCounter++)));
+
+ return dx11DepthStencilState;
+ }
+}
+
+std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState)
+{
+ static const unsigned int seed = 0xABCDEF98;
+
+ std::size_t hash = 0;
+ MurmurHash3_x86_32(&samplerState, sizeof(gl::SamplerState), seed, &hash);
+ return hash;
+}
+
+bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b)
+{
+ return memcmp(&a, &b, sizeof(gl::SamplerState)) == 0;
+}
+
+ID3D11SamplerState *RenderStateCache::getSamplerState(const gl::SamplerState &samplerState)
+{
+ if (!mDevice)
+ {
+ ERR("RenderStateCache is not initialized.");
+ return NULL;
+ }
+
+ SamplerStateMap::iterator i = mSamplerStateCache.find(samplerState);
+ if (i != mSamplerStateCache.end())
+ {
+ SamplerStateCounterPair &state = i->second;
+ state.second = mCounter++;
+ return state.first;
+ }
+ 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;
+ }
+ }
+ leastRecentlyUsed->second.first->Release();
+ mSamplerStateCache.erase(leastRecentlyUsed);
+ }
+
+ D3D11_SAMPLER_DESC samplerDesc;
+ samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, samplerState.maxAnisotropy);
+ samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS);
+ samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT);
+ samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.MipLODBias = static_cast<float>(samplerState.lodOffset);
+ samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy;
+ samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+ samplerDesc.BorderColor[0] = 0.0f;
+ samplerDesc.BorderColor[1] = 0.0f;
+ samplerDesc.BorderColor[2] = 0.0f;
+ samplerDesc.BorderColor[3] = 0.0f;
+ samplerDesc.MinLOD = gl_d3d11::ConvertMinLOD(samplerState.minFilter, samplerState.lodOffset);
+ samplerDesc.MaxLOD = gl_d3d11::ConvertMaxLOD(samplerState.minFilter, samplerState.lodOffset);
+
+ ID3D11SamplerState *dx11SamplerState = NULL;
+ HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState);
+ if (FAILED(result) || !dx11SamplerState)
+ {
+ ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result);
+ return NULL;
+ }
+
+ mSamplerStateCache.insert(std::make_pair(samplerState, std::make_pair(dx11SamplerState, mCounter++)));
+
+ return dx11SamplerState;
+ }
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/RenderStateCache.h b/src/libGLESv2/renderer/RenderStateCache.h
new file mode 100644
index 00000000..f8b5111d
--- /dev/null
+++ b/src/libGLESv2/renderer/RenderStateCache.h
@@ -0,0 +1,101 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RenderStateCache.h: Defines rx::RenderStateCache, a cache of Direct3D render
+// state objects.
+
+#ifndef LIBGLESV2_RENDERER_RENDERSTATECACHE_H_
+#define LIBGLESV2_RENDERER_RENDERSTATECACHE_H_
+
+#include "libGLESv2/angletypes.h"
+#include "common/angleutils.h"
+
+namespace rx
+{
+
+class RenderStateCache
+{
+ public:
+ RenderStateCache();
+ virtual ~RenderStateCache();
+
+ void initialize(ID3D11Device *device);
+ void clear();
+
+ // Increments refcount on the returned blend state, Release() must be called.
+ ID3D11BlendState *getBlendState(const gl::BlendState &blendState);
+ ID3D11RasterizerState *getRasterizerState(const gl::RasterizerState &rasterState,
+ bool scissorEnabled, unsigned int depthSize);
+ ID3D11DepthStencilState *getDepthStencilState(const gl::DepthStencilState &dsState);
+ ID3D11SamplerState *getSamplerState(const gl::SamplerState &samplerState);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderStateCache);
+
+ unsigned long long mCounter;
+
+ // Blend state cache
+ static std::size_t hashBlendState(const gl::BlendState &blendState);
+ static bool compareBlendStates(const gl::BlendState &a, const gl::BlendState &b);
+ static const unsigned int kMaxBlendStates;
+
+ typedef std::size_t (*BlendStateHashFunction)(const gl::BlendState &);
+ typedef bool (*BlendStateEqualityFunction)(const gl::BlendState &, const gl::BlendState &);
+ typedef std::pair<ID3D11BlendState*, unsigned long long> BlendStateCounterPair;
+ typedef std::unordered_map<gl::BlendState, BlendStateCounterPair, BlendStateHashFunction, BlendStateEqualityFunction> BlendStateMap;
+ BlendStateMap mBlendStateCache;
+
+ // Rasterizer state cache
+ struct RasterizerStateKey
+ {
+ gl::RasterizerState rasterizerState;
+ bool scissorEnabled;
+ unsigned int depthSize;
+ };
+ 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<ID3D11RasterizerState*, unsigned long long> RasterizerStateCounterPair;
+ typedef std::unordered_map<RasterizerStateKey, RasterizerStateCounterPair, RasterizerStateHashFunction, RasterizerStateEqualityFunction> RasterizerStateMap;
+ RasterizerStateMap mRasterizerStateCache;
+
+ // Depth stencil state cache
+ static std::size_t hashDepthStencilState(const gl::DepthStencilState &dsState);
+ static bool compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b);
+ static const unsigned int kMaxDepthStencilStates;
+
+ typedef std::size_t (*DepthStencilStateHashFunction)(const gl::DepthStencilState &);
+ typedef bool (*DepthStencilStateEqualityFunction)(const gl::DepthStencilState &, const gl::DepthStencilState &);
+ typedef std::pair<ID3D11DepthStencilState*, unsigned long long> DepthStencilStateCounterPair;
+ typedef std::unordered_map<gl::DepthStencilState,
+ DepthStencilStateCounterPair,
+ DepthStencilStateHashFunction,
+ DepthStencilStateEqualityFunction> DepthStencilStateMap;
+ DepthStencilStateMap mDepthStencilStateCache;
+
+ // Sample state cache
+ static std::size_t hashSamplerState(const gl::SamplerState &samplerState);
+ static bool compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b);
+ static const unsigned int kMaxSamplerStates;
+
+ typedef std::size_t (*SamplerStateHashFunction)(const gl::SamplerState &);
+ typedef bool (*SamplerStateEqualityFunction)(const gl::SamplerState &, const gl::SamplerState &);
+ typedef std::pair<ID3D11SamplerState*, unsigned long long> SamplerStateCounterPair;
+ typedef std::unordered_map<gl::SamplerState,
+ SamplerStateCounterPair,
+ SamplerStateHashFunction,
+ SamplerStateEqualityFunction> SamplerStateMap;
+ SamplerStateMap mSamplerStateCache;
+
+ ID3D11Device *mDevice;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_RENDERSTATECACHE_H_ \ No newline at end of file
diff --git a/src/libGLESv2/renderer/RenderTarget.h b/src/libGLESv2/renderer/RenderTarget.h
new file mode 100644
index 00000000..80de39f4
--- /dev/null
+++ b/src/libGLESv2/renderer/RenderTarget.h
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RenderTarget.h: Defines an abstract wrapper class to manage IDirect3DSurface9
+// and ID3D11View objects belonging to renderbuffers.
+
+#ifndef LIBGLESV2_RENDERER_RENDERTARGET_H_
+#define LIBGLESV2_RENDERER_RENDERTARGET_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+class RenderTarget
+{
+ public:
+ RenderTarget()
+ {
+ mWidth = 0;
+ mHeight = 0;
+ mInternalFormat = GL_NONE;
+ mActualFormat = GL_NONE;
+ mSamples = 0;
+ }
+
+ virtual ~RenderTarget() {};
+
+ GLsizei getWidth() { return mWidth; }
+ GLsizei getHeight() { return mHeight; }
+ GLenum getInternalFormat() { return mInternalFormat; }
+ GLenum getActualFormat() { return mActualFormat; }
+ GLsizei getSamples() { return mSamples; }
+
+ struct Desc {
+ GLsizei width;
+ GLsizei height;
+ GLenum format;
+ };
+
+ protected:
+ GLsizei mWidth;
+ GLsizei mHeight;
+ GLenum mInternalFormat;
+ GLenum mActualFormat;
+ GLsizei mSamples;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderTarget);
+};
+
+}
+
+#endif // LIBGLESV2_RENDERTARGET_H_
diff --git a/src/libGLESv2/renderer/RenderTarget11.cpp b/src/libGLESv2/renderer/RenderTarget11.cpp
new file mode 100644
index 00000000..2667cc6f
--- /dev/null
+++ b/src/libGLESv2/renderer/RenderTarget11.cpp
@@ -0,0 +1,355 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RenderTarget11.cpp: Implements a DX11-specific wrapper for ID3D11View pointers
+// retained by Renderbuffers.
+
+#include "libGLESv2/renderer/RenderTarget11.h"
+#include "libGLESv2/renderer/Renderer11.h"
+
+#include "libGLESv2/renderer/renderer11_utils.h"
+#include "libGLESv2/main.h"
+
+namespace rx
+{
+
+static unsigned int getRTVSubresourceIndex(ID3D11Texture2D *texture, ID3D11RenderTargetView *view)
+{
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
+ view->GetDesc(&rtvDesc);
+
+ D3D11_TEXTURE2D_DESC texDesc;
+ texture->GetDesc(&texDesc);
+
+ unsigned int mipSlice = 0;
+ unsigned int arraySlice = 0;
+ unsigned int mipLevels = texDesc.MipLevels;
+
+ 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;
+ }
+
+ return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels);
+}
+
+static unsigned int getDSVSubresourceIndex(ID3D11Texture2D *texture, ID3D11DepthStencilView *view)
+{
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
+ view->GetDesc(&dsvDesc);
+
+ D3D11_TEXTURE2D_DESC texDesc;
+ texture->GetDesc(&texDesc);
+
+ unsigned int mipSlice = 0;
+ unsigned int arraySlice = 0;
+ unsigned int mipLevels = texDesc.MipLevels;
+
+ 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_RTV_DIMENSION_UNKNOWN:
+ UNIMPLEMENTED();
+ break;
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels);
+}
+
+RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Texture2D *tex, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height)
+{
+ mRenderer = Renderer11::makeRenderer11(renderer);
+ mTexture = tex;
+ mRenderTarget = rtv;
+ mDepthStencil = NULL;
+ mShaderResource = srv;
+ mSubresourceIndex = 0;
+
+ if (mRenderTarget && mTexture)
+ {
+ D3D11_RENDER_TARGET_VIEW_DESC desc;
+ mRenderTarget->GetDesc(&desc);
+
+ D3D11_TEXTURE2D_DESC texDesc;
+ mTexture->GetDesc(&texDesc);
+
+ mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget);
+ mWidth = width;
+ mHeight = height;
+ mSamples = (texDesc.SampleDesc.Count > 1) ? texDesc.SampleDesc.Count : 0;
+
+ mInternalFormat = d3d11_gl::ConvertTextureInternalFormat(desc.Format);
+ mActualFormat = d3d11_gl::ConvertTextureInternalFormat(desc.Format);
+ }
+}
+
+RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Texture2D *tex, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height)
+{
+ mRenderer = Renderer11::makeRenderer11(renderer);
+ mTexture = tex;
+ mRenderTarget = NULL;
+ mDepthStencil = dsv;
+ mShaderResource = srv;
+ mSubresourceIndex = 0;
+
+ if (mDepthStencil && mTexture)
+ {
+ D3D11_DEPTH_STENCIL_VIEW_DESC desc;
+ mDepthStencil->GetDesc(&desc);
+
+ D3D11_TEXTURE2D_DESC texDesc;
+ mTexture->GetDesc(&texDesc);
+
+ mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil);
+ mWidth = width;
+ mHeight = height;
+ mSamples = (texDesc.SampleDesc.Count > 1) ? texDesc.SampleDesc.Count : 0;
+
+ mInternalFormat = d3d11_gl::ConvertTextureInternalFormat(desc.Format);
+ mActualFormat = d3d11_gl::ConvertTextureInternalFormat(desc.Format);
+ }
+}
+
+RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples, bool depth)
+{
+ mRenderer = Renderer11::makeRenderer11(renderer);
+ mTexture = NULL;
+ mRenderTarget = NULL;
+ mDepthStencil = NULL;
+ mShaderResource = NULL;
+
+ DXGI_FORMAT requestedFormat = gl_d3d11::ConvertRenderbufferFormat(format);
+
+ int supportedSamples = mRenderer->getNearestSupportedSamples(requestedFormat, samples);
+ if (supportedSamples < 0)
+ {
+ gl::error(GL_OUT_OF_MEMORY);
+ return;
+ }
+
+ 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 = requestedFormat;
+ desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.CPUAccessFlags = 0;
+ desc.MiscFlags = 0;
+ desc.BindFlags = (depth ? D3D11_BIND_DEPTH_STENCIL : (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE));
+
+ ID3D11Device *device = mRenderer->getDevice();
+ HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ gl::error(GL_OUT_OF_MEMORY);
+ return;
+ }
+ ASSERT(SUCCEEDED(result));
+
+ if (depth)
+ {
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
+ dsvDesc.Format = requestedFormat;
+ dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS;
+ dsvDesc.Texture2D.MipSlice = 0;
+ dsvDesc.Flags = 0;
+ result = device->CreateDepthStencilView(mTexture, &dsvDesc, &mDepthStencil);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ gl::error(GL_OUT_OF_MEMORY);
+ }
+ ASSERT(SUCCEEDED(result));
+ }
+ else
+ {
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
+ rtvDesc.Format = requestedFormat;
+ rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS;
+ rtvDesc.Texture2D.MipSlice = 0;
+ result = device->CreateRenderTargetView(mTexture, &rtvDesc, &mRenderTarget);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ gl::error(GL_OUT_OF_MEMORY);
+ return;
+ }
+ ASSERT(SUCCEEDED(result));
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ srvDesc.Format = requestedFormat;
+ srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS;
+ srvDesc.Texture2D.MostDetailedMip = 0;
+ srvDesc.Texture2D.MipLevels = 1;
+ result = device->CreateShaderResourceView(mTexture, &srvDesc, &mShaderResource);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ mRenderTarget->Release();
+ mRenderTarget = NULL;
+ gl::error(GL_OUT_OF_MEMORY);
+ return;
+ }
+ ASSERT(SUCCEEDED(result));
+ }
+ }
+
+ mWidth = width;
+ mHeight = height;
+ mInternalFormat = format;
+ mSamples = supportedSamples;
+ mActualFormat = d3d11_gl::ConvertTextureInternalFormat(requestedFormat);
+ mSubresourceIndex = D3D11CalcSubresource(0, 0, 1);
+}
+
+RenderTarget11::~RenderTarget11()
+{
+ if (mTexture)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ }
+
+ if (mRenderTarget)
+ {
+ mRenderTarget->Release();
+ mRenderTarget = NULL;
+ }
+
+ if (mDepthStencil)
+ {
+ mDepthStencil->Release();
+ mDepthStencil = NULL;
+ }
+
+ if (mShaderResource)
+ {
+ mShaderResource->Release();
+ mShaderResource = NULL;
+ }
+}
+
+RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTarget *target)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(rx::RenderTarget11*, target));
+ return static_cast<rx::RenderTarget11*>(target);
+}
+
+ID3D11Texture2D *RenderTarget11::getTexture() const
+{
+ return mTexture;
+}
+
+ID3D11RenderTargetView *RenderTarget11::getRenderTargetView() const
+{
+ return mRenderTarget;
+}
+
+ID3D11DepthStencilView *RenderTarget11::getDepthStencilView() const
+{
+ return mDepthStencil;
+}
+
+ID3D11ShaderResourceView *RenderTarget11::getShaderResourceView() const
+{
+ return mShaderResource;
+}
+
+unsigned int RenderTarget11::getSubresourceIndex() const
+{
+ return mSubresourceIndex;
+}
+
+}
diff --git a/src/libGLESv2/renderer/RenderTarget11.h b/src/libGLESv2/renderer/RenderTarget11.h
new file mode 100644
index 00000000..97827f26
--- /dev/null
+++ b/src/libGLESv2/renderer/RenderTarget11.h
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RenderTarget11.h: Defines a DX11-specific wrapper for ID3D11View pointers
+// retained by Renderbuffers.
+
+#ifndef LIBGLESV2_RENDERER_RENDERTARGET11_H_
+#define LIBGLESV2_RENDERER_RENDERTARGET11_H_
+
+#include "libGLESv2/renderer/RenderTarget.h"
+
+namespace rx
+{
+class Renderer;
+class Renderer11;
+
+class RenderTarget11 : public RenderTarget
+{
+ public:
+ RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Texture2D *tex, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height);
+ RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Texture2D *tex, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height);
+ RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples, bool depth);
+ virtual ~RenderTarget11();
+
+ static RenderTarget11 *makeRenderTarget11(RenderTarget *renderTarget);
+
+ ID3D11Texture2D *getTexture() const;
+ ID3D11RenderTargetView *getRenderTargetView() const;
+ ID3D11DepthStencilView *getDepthStencilView() const;
+ ID3D11ShaderResourceView *getShaderResourceView() const;
+
+ unsigned int getSubresourceIndex() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderTarget11);
+
+ unsigned int mSubresourceIndex;
+ ID3D11Texture2D *mTexture;
+ ID3D11RenderTargetView *mRenderTarget;
+ ID3D11DepthStencilView *mDepthStencil;
+ ID3D11ShaderResourceView *mShaderResource;
+
+ Renderer11 *mRenderer;
+};
+
+}
+
+#endif LIBGLESV2_RENDERER_RENDERTARGET11_H_ \ No newline at end of file
diff --git a/src/libGLESv2/renderer/RenderTarget9.cpp b/src/libGLESv2/renderer/RenderTarget9.cpp
new file mode 100644
index 00000000..a84c7090
--- /dev/null
+++ b/src/libGLESv2/renderer/RenderTarget9.cpp
@@ -0,0 +1,113 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RenderTarget9.cpp: Implements a D3D9-specific wrapper for IDirect3DSurface9
+// pointers retained by renderbuffers.
+
+#include "libGLESv2/renderer/RenderTarget9.h"
+#include "libGLESv2/renderer/Renderer9.h"
+
+#include "libGLESv2/renderer/renderer9_utils.h"
+#include "libGLESv2/main.h"
+
+namespace rx
+{
+
+RenderTarget9::RenderTarget9(Renderer *renderer, IDirect3DSurface9 *surface)
+{
+ mRenderer = Renderer9::makeRenderer9(renderer);
+ mRenderTarget = surface;
+
+ if (mRenderTarget)
+ {
+ D3DSURFACE_DESC description;
+ mRenderTarget->GetDesc(&description);
+
+ mWidth = description.Width;
+ mHeight = description.Height;
+
+ mInternalFormat = d3d9_gl::GetEquivalentFormat(description.Format);
+ mActualFormat = d3d9_gl::GetEquivalentFormat(description.Format);
+ mSamples = d3d9_gl::GetSamplesFromMultisampleType(description.MultiSampleType);
+ }
+}
+
+RenderTarget9::RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples)
+{
+ mRenderer = Renderer9::makeRenderer9(renderer);
+ mRenderTarget = NULL;
+
+ D3DFORMAT requestedFormat = gl_d3d9::ConvertRenderbufferFormat(format);
+ int supportedSamples = mRenderer->getNearestSupportedSamples(requestedFormat, samples);
+
+ if (supportedSamples == -1)
+ {
+ gl::error(GL_OUT_OF_MEMORY);
+
+ return;
+ }
+
+ HRESULT result = D3DERR_INVALIDCALL;
+
+ if (width > 0 && height > 0)
+ {
+ if (requestedFormat == D3DFMT_D24S8)
+ {
+ result = mRenderer->getDevice()->CreateDepthStencilSurface(width, height, requestedFormat,
+ gl_d3d9::GetMultisampleTypeFromSamples(supportedSamples),
+ 0, FALSE, &mRenderTarget, NULL);
+ }
+ else
+ {
+ result = mRenderer->getDevice()->CreateRenderTarget(width, height, requestedFormat,
+ gl_d3d9::GetMultisampleTypeFromSamples(supportedSamples),
+ 0, FALSE, &mRenderTarget, NULL);
+ }
+
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ gl::error(GL_OUT_OF_MEMORY);
+
+ return;
+ }
+
+ ASSERT(SUCCEEDED(result));
+ }
+
+ mWidth = width;
+ mHeight = height;
+ mInternalFormat = format;
+ mSamples = supportedSamples;
+ mActualFormat = d3d9_gl::GetEquivalentFormat(requestedFormat);
+}
+
+RenderTarget9::~RenderTarget9()
+{
+ if (mRenderTarget)
+ {
+ mRenderTarget->Release();
+ }
+}
+
+RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTarget *target)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(rx::RenderTarget9*, target));
+ return static_cast<rx::RenderTarget9*>(target);
+}
+
+IDirect3DSurface9 *RenderTarget9::getSurface()
+{
+ // Caller is responsible for releasing the returned surface reference.
+ if (mRenderTarget)
+ {
+ mRenderTarget->AddRef();
+ }
+
+ return mRenderTarget;
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/RenderTarget9.h b/src/libGLESv2/renderer/RenderTarget9.h
new file mode 100644
index 00000000..faf8ad1c
--- /dev/null
+++ b/src/libGLESv2/renderer/RenderTarget9.h
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RenderTarget9.h: Defines a D3D9-specific wrapper for IDirect3DSurface9 pointers
+// retained by Renderbuffers.
+
+#ifndef LIBGLESV2_RENDERER_RENDERTARGET9_H_
+#define LIBGLESV2_RENDERER_RENDERTARGET9_H_
+
+#include "libGLESv2/renderer/RenderTarget.h"
+
+namespace rx
+{
+class Renderer;
+class Renderer9;
+
+class RenderTarget9 : public RenderTarget
+{
+ public:
+ RenderTarget9(Renderer *renderer, IDirect3DSurface9 *surface);
+ RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples);
+ virtual ~RenderTarget9();
+
+ static RenderTarget9 *makeRenderTarget9(RenderTarget *renderTarget);
+ IDirect3DSurface9 *getSurface();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderTarget9);
+
+ IDirect3DSurface9 *mRenderTarget;
+
+ Renderer9 *mRenderer;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_RENDERTARGET9_H_
diff --git a/src/libGLESv2/renderer/Renderer.cpp b/src/libGLESv2/renderer/Renderer.cpp
new file mode 100644
index 00000000..6138e6d9
--- /dev/null
+++ b/src/libGLESv2/renderer/Renderer.cpp
@@ -0,0 +1,220 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderer.cpp: Implements EGL dependencies for creating and destroying Renderer instances.
+
+#include <EGL/eglext.h>
+#include "libGLESv2/main.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/renderer/Renderer9.h"
+#include "libGLESv2/renderer/Renderer11.h"
+#include "libGLESv2/utilities.h"
+
+#if !defined(ANGLE_ENABLE_D3D11)
+// Enables use of the Direct3D 11 API for a default display, when available
+#define ANGLE_ENABLE_D3D11 0
+#endif
+
+namespace rx
+{
+
+Renderer::Renderer(egl::Display *display) : mDisplay(display)
+{
+ mD3dCompilerModule = NULL;
+ mD3DCompileFunc = NULL;
+}
+
+Renderer::~Renderer()
+{
+ if (mD3dCompilerModule)
+ {
+ FreeLibrary(mD3dCompilerModule);
+ mD3dCompilerModule = NULL;
+ }
+}
+
+bool Renderer::initializeCompiler()
+{
+#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES)
+ // Find a D3DCompiler module that had already been loaded based on a predefined list of versions.
+ static TCHAR* d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES;
+
+ for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i)
+ {
+ if (GetModuleHandleEx(0, d3dCompilerNames[i], &mD3dCompilerModule))
+ {
+ break;
+ }
+ }
+#else
+ // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with.
+ mD3dCompilerModule = LoadLibrary(D3DCOMPILER_DLL);
+#endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES
+
+ if (!mD3dCompilerModule)
+ {
+ ERR("No D3D compiler module found - aborting!\n");
+ return false;
+ }
+
+ mD3DCompileFunc = reinterpret_cast<pCompileFunc>(GetProcAddress(mD3dCompilerModule, "D3DCompile"));
+ ASSERT(mD3DCompileFunc);
+
+ return mD3DCompileFunc != NULL;
+}
+
+// Compiles HLSL code into executable binaries
+ShaderBlob *Renderer::compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, UINT optimizationFlags, bool alternateFlags)
+{
+ if (!hlsl)
+ {
+ return NULL;
+ }
+
+ HRESULT result = S_OK;
+ UINT flags = 0;
+ std::string sourceText;
+ if (gl::perfActive())
+ {
+ flags |= D3DCOMPILE_DEBUG;
+
+#ifdef NDEBUG
+ flags |= optimizationFlags;
+#else
+ flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
+#endif
+
+ std::string sourcePath = getTempPath();
+ sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
+ writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
+ }
+ else
+ {
+ flags |= optimizationFlags;
+ sourceText = hlsl;
+ }
+
+ // 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.
+ const static UINT extraFlags[] =
+ {
+ 0,
+ D3DCOMPILE_AVOID_FLOW_CONTROL,
+ D3DCOMPILE_PREFER_FLOW_CONTROL
+ };
+
+ const static char * const extraFlagNames[] =
+ {
+ "default",
+ "avoid flow control",
+ "prefer flow control"
+ };
+
+ int attempts = alternateFlags ? ArraySize(extraFlags) : 1;
+ pD3DCompile compileFunc = reinterpret_cast<pD3DCompile>(mD3DCompileFunc);
+ for (int i = 0; i < attempts; ++i)
+ {
+ ID3DBlob *errorMessage = NULL;
+ ID3DBlob *binary = NULL;
+
+ result = compileFunc(hlsl, strlen(hlsl), gl::g_fakepath, NULL, NULL,
+ "main", profile, flags | extraFlags[i], 0, &binary, &errorMessage);
+ if (errorMessage)
+ {
+ const char *message = (const char*)errorMessage->GetBufferPointer();
+
+ infoLog.appendSanitized(message);
+ TRACE("\n%s", hlsl);
+ TRACE("\n%s", message);
+
+ errorMessage->Release();
+ errorMessage = NULL;
+ }
+
+ if (SUCCEEDED(result))
+ {
+ return (ShaderBlob*)binary;
+ }
+ else
+ {
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, (ShaderBlob*) NULL);
+ }
+
+ infoLog.append("Warning: D3D shader compilation failed with ");
+ infoLog.append(extraFlagNames[i]);
+ infoLog.append(" flags.");
+ if (i + 1 < attempts)
+ {
+ infoLog.append(" Retrying with ");
+ infoLog.append(extraFlagNames[i + 1]);
+ infoLog.append(".\n");
+ }
+ }
+ }
+
+ return NULL;
+}
+
+}
+
+extern "C"
+{
+
+rx::Renderer *glCreateRenderer(egl::Display *display, HDC hDc, EGLNativeDisplayType displayId)
+{
+ rx::Renderer *renderer = NULL;
+ EGLint status = EGL_BAD_ALLOC;
+
+ if (ANGLE_ENABLE_D3D11 ||
+ displayId == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ||
+ displayId == EGL_D3D11_ONLY_DISPLAY_ANGLE)
+ {
+ renderer = new rx::Renderer11(display, hDc);
+
+ if (renderer)
+ {
+ status = renderer->initialize();
+ }
+
+ if (status == EGL_SUCCESS)
+ {
+ return renderer;
+ }
+ else if (displayId == EGL_D3D11_ONLY_DISPLAY_ANGLE)
+ {
+ return NULL;
+ }
+
+ // Failed to create a D3D11 renderer, try creating a D3D9 renderer
+ delete renderer;
+ }
+
+ bool softwareDevice = (displayId == EGL_SOFTWARE_DISPLAY_ANGLE);
+ renderer = new rx::Renderer9(display, hDc, softwareDevice);
+
+ if (renderer)
+ {
+ status = renderer->initialize();
+ }
+
+ if (status == EGL_SUCCESS)
+ {
+ return renderer;
+ }
+
+ return NULL;
+}
+
+void glDestroyRenderer(rx::Renderer *renderer)
+{
+ delete renderer;
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/Renderer.h b/src/libGLESv2/renderer/Renderer.h
new file mode 100644
index 00000000..04e877ba
--- /dev/null
+++ b/src/libGLESv2/renderer/Renderer.h
@@ -0,0 +1,244 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderer.h: Defines a back-end specific class that hides the details of the
+// implementation-specific renderer.
+
+#ifndef LIBGLESV2_RENDERER_RENDERER_H_
+#define LIBGLESV2_RENDERER_RENDERER_H_
+
+#include "libGLESv2/Uniform.h"
+#include "libGLESv2/angletypes.h"
+
+#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
+#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
+#endif
+
+const int versionWindowsVista = MAKEWORD(0x00, 0x06);
+const int versionWindows7 = MAKEWORD(0x01, 0x06);
+
+// Return the version of the operating system in a format suitable for ordering
+// comparison.
+inline int getComparableOSVersion()
+{
+ DWORD version = GetVersion();
+ int majorVersion = LOBYTE(LOWORD(version));
+ int minorVersion = HIBYTE(LOWORD(version));
+ return MAKEWORD(minorVersion, majorVersion);
+}
+
+namespace egl
+{
+class Display;
+}
+
+namespace gl
+{
+class InfoLog;
+class ProgramBinary;
+class VertexAttribute;
+class Buffer;
+class Texture;
+class Framebuffer;
+}
+
+namespace rx
+{
+class TextureStorageInterface2D;
+class TextureStorageInterfaceCube;
+class VertexBuffer;
+class IndexBuffer;
+class QueryImpl;
+class FenceImpl;
+class BufferStorage;
+class Blit;
+struct TranslatedIndexData;
+class ShaderExecutable;
+class SwapChain;
+class RenderTarget;
+class Image;
+class TextureStorage;
+
+typedef void * ShaderBlob;
+typedef void (*pCompileFunc)();
+
+struct ConfigDesc
+{
+ GLenum renderTargetFormat;
+ GLenum depthStencilFormat;
+ GLint multiSample;
+ bool fastConfig;
+};
+
+struct dx_VertexConstants
+{
+ float depthRange[4];
+ float viewAdjust[4];
+};
+
+struct dx_PixelConstants
+{
+ float depthRange[4];
+ float viewCoords[4];
+ float depthFront[4];
+};
+
+enum ShaderType
+{
+ SHADER_VERTEX,
+ SHADER_PIXEL,
+ SHADER_GEOMETRY
+};
+
+class Renderer
+{
+ public:
+ explicit Renderer(egl::Display *display);
+ virtual ~Renderer();
+
+ virtual EGLint initialize() = 0;
+ virtual bool resetDevice() = 0;
+
+ virtual int generateConfigs(ConfigDesc **configDescList) = 0;
+ virtual void deleteConfigs(ConfigDesc *configDescList) = 0;
+
+ virtual void sync(bool block) = 0;
+
+ virtual SwapChain *createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0;
+
+ virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler) = 0;
+ virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0;
+
+ virtual void setRasterizerState(const gl::RasterizerState &rasterState) = 0;
+ virtual void setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor,
+ unsigned int sampleMask) = 0;
+ virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
+ int stencilBackRef, bool frontFaceCCW) = 0;
+
+ virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled) = 0;
+ virtual bool setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
+ bool ignoreViewport) = 0;
+
+ virtual bool applyRenderTarget(gl::Framebuffer *frameBuffer) = 0;
+ virtual void applyShaders(gl::ProgramBinary *programBinary) = 0;
+ virtual void applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray) = 0;
+ virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount) = 0;
+ virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances) = 0;
+ virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0;
+
+ virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances) = 0;
+ virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0;
+
+ virtual void clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) = 0;
+
+ virtual void markAllStateDirty() = 0;
+
+ // lost device
+ virtual void notifyDeviceLost() = 0;
+ virtual bool isDeviceLost() = 0;
+ virtual bool testDeviceLost(bool notify) = 0;
+ virtual bool testDeviceResettable() = 0;
+
+ // Renderer capabilities
+ virtual DWORD getAdapterVendor() const = 0;
+ virtual std::string getRendererDescription() const = 0;
+ virtual GUID getAdapterIdentifier() const = 0;
+
+ virtual bool getBGRATextureSupport() const = 0;
+ virtual bool getDXT1TextureSupport() = 0;
+ virtual bool getDXT3TextureSupport() = 0;
+ virtual bool getDXT5TextureSupport() = 0;
+ virtual bool getEventQuerySupport() = 0;
+ virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable) = 0;
+ virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable) = 0;
+ virtual bool getLuminanceTextureSupport() = 0;
+ virtual bool getLuminanceAlphaTextureSupport() = 0;
+ bool getVertexTextureSupport() const { return getMaxVertexTextureImageUnits() > 0; }
+ virtual unsigned int getMaxVertexTextureImageUnits() const = 0;
+ virtual unsigned int getMaxCombinedTextureImageUnits() const = 0;
+ virtual unsigned int getReservedVertexUniformVectors() const = 0;
+ virtual unsigned int getReservedFragmentUniformVectors() const = 0;
+ virtual unsigned int getMaxVertexUniformVectors() const = 0;
+ virtual unsigned int getMaxFragmentUniformVectors() const = 0;
+ virtual unsigned int getMaxVaryingVectors() const = 0;
+ virtual bool getNonPower2TextureSupport() const = 0;
+ virtual bool getDepthTextureSupport() const = 0;
+ virtual bool getOcclusionQuerySupport() const = 0;
+ virtual bool getInstancingSupport() const = 0;
+ virtual bool getTextureFilterAnisotropySupport() const = 0;
+ virtual float getTextureMaxAnisotropy() const = 0;
+ virtual bool getShareHandleSupport() const = 0;
+ virtual bool getDerivativeInstructionSupport() const = 0;
+ virtual bool getPostSubBufferSupport() const = 0;
+
+ virtual int getMajorShaderModel() const = 0;
+ virtual float getMaxPointSize() const = 0;
+ virtual int getMaxViewportDimension() const = 0;
+ virtual int getMaxTextureWidth() const = 0;
+ virtual int getMaxTextureHeight() const = 0;
+ virtual bool get32BitIndexSupport() const = 0;
+ virtual int getMinSwapInterval() const = 0;
+ virtual int getMaxSwapInterval() const = 0;
+
+ virtual GLsizei getMaxSupportedSamples() const = 0;
+
+ virtual unsigned int getMaxRenderTargets() const = 0;
+
+ // Pixel operations
+ virtual bool copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source) = 0;
+ virtual bool copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source) = 0;
+
+ virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level) = 0;
+ virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level) = 0;
+
+ virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect,
+ bool blitRenderTarget, bool blitDepthStencil) = 0;
+ virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels) = 0;
+
+ // RenderTarget creation
+ virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth) = 0;
+ virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth) = 0;
+
+ // Shader operations
+ virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type) = 0;
+ virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type) = 0;
+
+ // Image operations
+ virtual Image *createImage() = 0;
+ virtual void generateMipmap(Image *dest, Image *source) = 0;
+ virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain) = 0;
+ virtual TextureStorage *createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height) = 0;
+ virtual TextureStorage *createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size) = 0;
+
+ // Buffer creation
+ virtual VertexBuffer *createVertexBuffer() = 0;
+ virtual IndexBuffer *createIndexBuffer() = 0;
+ virtual BufferStorage *createBufferStorage() = 0;
+
+ // Query and Fence creation
+ virtual QueryImpl *createQuery(GLenum type) = 0;
+ virtual FenceImpl *createFence() = 0;
+
+ virtual bool getLUID(LUID *adapterLuid) const = 0;
+
+ protected:
+ bool initializeCompiler();
+ ShaderBlob *compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, UINT optimizationFlags, bool alternateFlags);
+
+ egl::Display *mDisplay;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Renderer);
+
+ HMODULE mD3dCompilerModule;
+ pCompileFunc mD3DCompileFunc;
+};
+
+}
+#endif // LIBGLESV2_RENDERER_RENDERER_H_
diff --git a/src/libGLESv2/renderer/Renderer11.cpp b/src/libGLESv2/renderer/Renderer11.cpp
new file mode 100644
index 00000000..9173fc8c
--- /dev/null
+++ b/src/libGLESv2/renderer/Renderer11.cpp
@@ -0,0 +1,3535 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer.
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/RenderBuffer.h"
+#include "libGLESv2/renderer/Renderer11.h"
+#include "libGLESv2/renderer/RenderTarget11.h"
+#include "libGLESv2/renderer/renderer11_utils.h"
+#include "libGLESv2/renderer/ShaderExecutable11.h"
+#include "libGLESv2/renderer/SwapChain11.h"
+#include "libGLESv2/renderer/Image11.h"
+#include "libGLESv2/renderer/VertexBuffer11.h"
+#include "libGLESv2/renderer/IndexBuffer11.h"
+#include "libGLESv2/renderer/BufferStorage11.h"
+#include "libGLESv2/renderer/VertexDataManager.h"
+#include "libGLESv2/renderer/IndexDataManager.h"
+#include "libGLESv2/renderer/TextureStorage11.h"
+#include "libGLESv2/renderer/Query11.h"
+#include "libGLESv2/renderer/Fence11.h"
+
+#include "libGLESv2/renderer/shaders/compiled/passthrough11vs.h"
+#include "libGLESv2/renderer/shaders/compiled/passthroughrgba11ps.h"
+#include "libGLESv2/renderer/shaders/compiled/passthroughrgb11ps.h"
+#include "libGLESv2/renderer/shaders/compiled/passthroughlum11ps.h"
+#include "libGLESv2/renderer/shaders/compiled/passthroughlumalpha11ps.h"
+
+#include "libGLESv2/renderer/shaders/compiled/clear11vs.h"
+#include "libGLESv2/renderer/shaders/compiled/clearsingle11ps.h"
+#include "libGLESv2/renderer/shaders/compiled/clearmultiple11ps.h"
+
+#include "libEGL/Display.h"
+
+#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
+{
+static const DXGI_FORMAT RenderTargetFormats[] =
+ {
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ DXGI_FORMAT_R8G8B8A8_UNORM
+ };
+
+static const DXGI_FORMAT DepthStencilFormats[] =
+ {
+ DXGI_FORMAT_UNKNOWN,
+ DXGI_FORMAT_D24_UNORM_S8_UINT,
+ DXGI_FORMAT_D16_UNORM
+ };
+
+enum
+{
+ MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16
+};
+
+Renderer11::Renderer11(egl::Display *display, HDC hDc) : Renderer(display), mDc(hDc)
+{
+ mVertexDataManager = NULL;
+ mIndexDataManager = NULL;
+
+ mLineLoopIB = NULL;
+ mTriangleFanIB = NULL;
+
+ mCopyResourcesInitialized = false;
+ mCopyVB = NULL;
+ mCopySampler = NULL;
+ mCopyIL = NULL;
+ mCopyVS = NULL;
+ mCopyRGBAPS = NULL;
+ mCopyRGBPS = NULL;
+ mCopyLumPS = NULL;
+ mCopyLumAlphaPS = NULL;
+
+ mClearResourcesInitialized = false;
+ mClearVB = NULL;
+ mClearIL = NULL;
+ mClearVS = NULL;
+ mClearSinglePS = NULL;
+ mClearMultiplePS = NULL;
+ mClearScissorRS = NULL;
+ mClearNoScissorRS = NULL;
+
+ mSyncQuery = NULL;
+
+ mD3d11Module = NULL;
+ mDxgiModule = NULL;
+
+ mDeviceLost = false;
+
+ mMaxSupportedSamples = 0;
+
+ mDevice = NULL;
+ mDeviceContext = NULL;
+ mDxgiAdapter = NULL;
+ mDxgiFactory = NULL;
+
+ mDriverConstantBufferVS = NULL;
+ mDriverConstantBufferPS = NULL;
+
+ mBGRATextureSupport = false;
+
+ mIsGeometryShaderActive = false;
+}
+
+Renderer11::~Renderer11()
+{
+ release();
+}
+
+Renderer11 *Renderer11::makeRenderer11(Renderer *renderer)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(rx::Renderer11*, renderer));
+ return static_cast<rx::Renderer11*>(renderer);
+}
+
+#ifndef __d3d11_1_h__
+#define D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET ((D3D11_MESSAGE_ID)3146081)
+#endif
+
+EGLint Renderer11::initialize()
+{
+ if (!initializeCompiler())
+ {
+ return EGL_NOT_INITIALIZED;
+ }
+
+ mDxgiModule = LoadLibrary(TEXT("dxgi.dll"));
+ mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
+
+ if (mD3d11Module == NULL || mDxgiModule == NULL)
+ {
+ ERR("Could not load D3D11 or DXGI library - aborting!\n");
+ return EGL_NOT_INITIALIZED;
+ }
+
+ // create the D3D11 device
+ ASSERT(mDevice == NULL);
+ PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice");
+
+ if (D3D11CreateDevice == NULL)
+ {
+ ERR("Could not retrieve D3D11CreateDevice address - aborting!\n");
+ return EGL_NOT_INITIALIZED;
+ }
+
+ D3D_FEATURE_LEVEL featureLevels[] =
+ {
+ D3D_FEATURE_LEVEL_11_0,
+ D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0,
+ };
+
+ HRESULT result = S_OK;
+
+#ifdef _DEBUG
+ result = D3D11CreateDevice(NULL,
+ D3D_DRIVER_TYPE_HARDWARE,
+ NULL,
+ D3D11_CREATE_DEVICE_DEBUG,
+ featureLevels,
+ ArraySize(featureLevels),
+ D3D11_SDK_VERSION,
+ &mDevice,
+ &mFeatureLevel,
+ &mDeviceContext);
+
+ if (!mDevice || FAILED(result))
+ {
+ ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n");
+ }
+
+ if (!mDevice || FAILED(result))
+#endif
+ {
+ result = D3D11CreateDevice(NULL,
+ D3D_DRIVER_TYPE_HARDWARE,
+ NULL,
+ 0,
+ featureLevels,
+ ArraySize(featureLevels),
+ D3D11_SDK_VERSION,
+ &mDevice,
+ &mFeatureLevel,
+ &mDeviceContext);
+
+ if (!mDevice || FAILED(result))
+ {
+ ERR("Could not create D3D11 device - aborting!\n");
+ return EGL_NOT_INITIALIZED; // Cleanup done by destructor through glDestroyRenderer
+ }
+ }
+
+ IDXGIDevice *dxgiDevice = NULL;
+ result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
+
+ if (FAILED(result))
+ {
+ ERR("Could not query DXGI device - aborting!\n");
+ return EGL_NOT_INITIALIZED;
+ }
+
+ result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter);
+
+ if (FAILED(result))
+ {
+ ERR("Could not retrieve DXGI adapter - aborting!\n");
+ return EGL_NOT_INITIALIZED;
+ }
+
+ dxgiDevice->Release();
+
+ mDxgiAdapter->GetDesc(&mAdapterDescription);
+ memset(mDescription, 0, sizeof(mDescription));
+ wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1);
+
+ result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory);
+
+ if (!mDxgiFactory || FAILED(result))
+ {
+ ERR("Could not create DXGI factory - aborting!\n");
+ return EGL_NOT_INITIALIZED;
+ }
+
+ // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log
+#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG)
+ ID3D11InfoQueue *infoQueue;
+ result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue);
+
+ if (SUCCEEDED(result))
+ {
+ D3D11_MESSAGE_ID hideMessages[] =
+ {
+ D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETS_HAZARD,
+ D3D11_MESSAGE_ID_DEVICE_PSSETSHADERRESOURCES_HAZARD,
+ D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET
+ };
+
+ D3D11_INFO_QUEUE_FILTER filter = {0};
+ filter.DenyList.NumIDs = ArraySize(hideMessages);
+ filter.DenyList.pIDList = hideMessages;
+
+ infoQueue->AddStorageFilterEntries(&filter);
+
+ infoQueue->Release();
+ }
+#endif
+
+ unsigned int maxSupportedSamples = 0;
+ unsigned int rtFormatCount = ArraySize(RenderTargetFormats);
+ unsigned int dsFormatCount = ArraySize(DepthStencilFormats);
+ for (unsigned int i = 0; i < rtFormatCount + dsFormatCount; ++i)
+ {
+ DXGI_FORMAT format = (i < rtFormatCount) ? RenderTargetFormats[i] : DepthStencilFormats[i - rtFormatCount];
+ if (format != DXGI_FORMAT_UNKNOWN)
+ {
+ UINT formatSupport;
+ result = mDevice->CheckFormatSupport(format, &formatSupport);
+ if (SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET))
+ {
+ MultisampleSupportInfo supportInfo;
+
+ for (unsigned int j = 1; j <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; j++)
+ {
+ result = mDevice->CheckMultisampleQualityLevels(format, j, &supportInfo.qualityLevels[j - 1]);
+ if (SUCCEEDED(result) && supportInfo.qualityLevels[j - 1] > 0)
+ {
+ maxSupportedSamples = std::max(j, maxSupportedSamples);
+ }
+ else
+ {
+ supportInfo.qualityLevels[j - 1] = 0;
+ }
+ }
+
+ mMultisampleSupportMap.insert(std::make_pair(format, supportInfo));
+ }
+ }
+ }
+ mMaxSupportedSamples = maxSupportedSamples;
+
+ initializeDevice();
+
+ // BGRA texture support is optional in feature levels 10 and 10_1
+ UINT formatSupport;
+ result = mDevice->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &formatSupport);
+ if (FAILED(result))
+ {
+ ERR("Error checking BGRA format support: 0x%08X", result);
+ }
+ else
+ {
+ const int flags = (D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET);
+ mBGRATextureSupport = (formatSupport & flags) == flags;
+ }
+
+ // Check floating point texture support
+ static const unsigned int requiredTextureFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE;
+ static const unsigned int requiredRenderableFlags = D3D11_FORMAT_SUPPORT_RENDER_TARGET;
+ static const unsigned int requiredFilterFlags = D3D11_FORMAT_SUPPORT_SHADER_SAMPLE;
+
+ DXGI_FORMAT float16Formats[] =
+ {
+ DXGI_FORMAT_R16_FLOAT,
+ DXGI_FORMAT_R16G16_FLOAT,
+ DXGI_FORMAT_R16G16B16A16_FLOAT,
+ };
+
+ DXGI_FORMAT float32Formats[] =
+ {
+ DXGI_FORMAT_R32_FLOAT,
+ DXGI_FORMAT_R32G32_FLOAT,
+ DXGI_FORMAT_R32G32B32_FLOAT,
+ DXGI_FORMAT_R32G32B32A32_FLOAT,
+ };
+
+ mFloat16TextureSupport = true;
+ mFloat16FilterSupport = true;
+ mFloat16RenderSupport = true;
+ for (unsigned int i = 0; i < ArraySize(float16Formats); i++)
+ {
+ if (SUCCEEDED(mDevice->CheckFormatSupport(float16Formats[i], &formatSupport)))
+ {
+ mFloat16TextureSupport = mFloat16TextureSupport && (formatSupport & requiredTextureFlags) == requiredTextureFlags;
+ mFloat16FilterSupport = mFloat16FilterSupport && (formatSupport & requiredFilterFlags) == requiredFilterFlags;
+ mFloat16RenderSupport = mFloat16RenderSupport && (formatSupport & requiredRenderableFlags) == requiredRenderableFlags;
+ }
+ else
+ {
+ mFloat16TextureSupport = false;
+ mFloat16RenderSupport = false;
+ mFloat16FilterSupport = false;
+ }
+ }
+
+ mFloat32TextureSupport = true;
+ mFloat32FilterSupport = true;
+ mFloat32RenderSupport = true;
+ for (unsigned int i = 0; i < ArraySize(float32Formats); i++)
+ {
+ if (SUCCEEDED(mDevice->CheckFormatSupport(float32Formats[i], &formatSupport)))
+ {
+ mFloat32TextureSupport = mFloat32TextureSupport && (formatSupport & requiredTextureFlags) == requiredTextureFlags;
+ mFloat32FilterSupport = mFloat32FilterSupport && (formatSupport & requiredFilterFlags) == requiredFilterFlags;
+ mFloat32RenderSupport = mFloat32RenderSupport && (formatSupport & requiredRenderableFlags) == requiredRenderableFlags;
+ }
+ else
+ {
+ mFloat32TextureSupport = false;
+ mFloat32FilterSupport = false;
+ mFloat32RenderSupport = false;
+ }
+ }
+
+ // Check compressed texture support
+ const unsigned int requiredCompressedTextureFlags = D3D11_FORMAT_SUPPORT_TEXTURE2D;
+
+ if (SUCCEEDED(mDevice->CheckFormatSupport(DXGI_FORMAT_BC1_UNORM, &formatSupport)))
+ {
+ mDXT1TextureSupport = (formatSupport & requiredCompressedTextureFlags) == requiredCompressedTextureFlags;
+ }
+ else
+ {
+ mDXT1TextureSupport = false;
+ }
+
+ if (SUCCEEDED(mDevice->CheckFormatSupport(DXGI_FORMAT_BC3_UNORM, &formatSupport)))
+ {
+ mDXT3TextureSupport = (formatSupport & requiredCompressedTextureFlags) == requiredCompressedTextureFlags;
+ }
+ else
+ {
+ mDXT3TextureSupport = false;
+ }
+
+ if (SUCCEEDED(mDevice->CheckFormatSupport(DXGI_FORMAT_BC5_UNORM, &formatSupport)))
+ {
+ mDXT5TextureSupport = (formatSupport & requiredCompressedTextureFlags) == requiredCompressedTextureFlags;
+ }
+ else
+ {
+ mDXT5TextureSupport = false;
+ }
+
+ // Check depth texture support
+ DXGI_FORMAT depthTextureFormats[] =
+ {
+ DXGI_FORMAT_D16_UNORM,
+ DXGI_FORMAT_D24_UNORM_S8_UINT,
+ };
+
+ static const unsigned int requiredDepthTextureFlags = D3D11_FORMAT_SUPPORT_DEPTH_STENCIL |
+ D3D11_FORMAT_SUPPORT_TEXTURE2D;
+
+ mDepthTextureSupport = true;
+ for (unsigned int i = 0; i < ArraySize(depthTextureFormats); i++)
+ {
+ if (SUCCEEDED(mDevice->CheckFormatSupport(depthTextureFormats[i], &formatSupport)))
+ {
+ mDepthTextureSupport = mDepthTextureSupport && ((formatSupport & requiredDepthTextureFlags) == requiredDepthTextureFlags);
+ }
+ else
+ {
+ mDepthTextureSupport = false;
+ }
+ }
+
+ return EGL_SUCCESS;
+}
+
+// do any one-time device initialization
+// NOTE: this is also needed after a device lost/reset
+// to reset the scene status and ensure the default states are reset.
+void Renderer11::initializeDevice()
+{
+ mStateCache.initialize(mDevice);
+ mInputLayoutCache.initialize(mDevice, mDeviceContext);
+
+ ASSERT(!mVertexDataManager && !mIndexDataManager);
+ mVertexDataManager = new VertexDataManager(this);
+ mIndexDataManager = new IndexDataManager(this);
+
+ markAllStateDirty();
+}
+
+int Renderer11::generateConfigs(ConfigDesc **configDescList)
+{
+ unsigned int numRenderFormats = ArraySize(RenderTargetFormats);
+ unsigned int numDepthFormats = ArraySize(DepthStencilFormats);
+ (*configDescList) = new ConfigDesc[numRenderFormats * numDepthFormats];
+ int numConfigs = 0;
+
+ for (unsigned int formatIndex = 0; formatIndex < numRenderFormats; formatIndex++)
+ {
+ for (unsigned int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++)
+ {
+ DXGI_FORMAT renderTargetFormat = RenderTargetFormats[formatIndex];
+
+ UINT formatSupport = 0;
+ HRESULT result = mDevice->CheckFormatSupport(renderTargetFormat, &formatSupport);
+
+ if (SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET))
+ {
+ DXGI_FORMAT depthStencilFormat = DepthStencilFormats[depthStencilIndex];
+
+ bool depthStencilFormatOK = true;
+
+ if (depthStencilFormat != DXGI_FORMAT_UNKNOWN)
+ {
+ UINT formatSupport = 0;
+ result = mDevice->CheckFormatSupport(depthStencilFormat, &formatSupport);
+ depthStencilFormatOK = SUCCEEDED(result) && (formatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL);
+ }
+
+ if (depthStencilFormatOK)
+ {
+ ConfigDesc newConfig;
+ newConfig.renderTargetFormat = d3d11_gl::ConvertBackBufferFormat(renderTargetFormat);
+ newConfig.depthStencilFormat = d3d11_gl::ConvertDepthStencilFormat(depthStencilFormat);
+ newConfig.multiSample = 0; // FIXME: enumerate multi-sampling
+ newConfig.fastConfig = true; // Assume all DX11 format conversions to be fast
+
+ (*configDescList)[numConfigs++] = newConfig;
+ }
+ }
+ }
+ }
+
+ return numConfigs;
+}
+
+void Renderer11::deleteConfigs(ConfigDesc *configDescList)
+{
+ delete [] (configDescList);
+}
+
+void Renderer11::sync(bool block)
+{
+ if (block)
+ {
+ HRESULT result;
+
+ if (!mSyncQuery)
+ {
+ D3D11_QUERY_DESC queryDesc;
+ queryDesc.Query = D3D11_QUERY_EVENT;
+ queryDesc.MiscFlags = 0;
+
+ result = mDevice->CreateQuery(&queryDesc, &mSyncQuery);
+ ASSERT(SUCCEEDED(result));
+ }
+
+ mDeviceContext->End(mSyncQuery);
+ mDeviceContext->Flush();
+
+ do
+ {
+ result = mDeviceContext->GetData(mSyncQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH);
+
+ // Keep polling, but allow other threads to do something useful first
+ Sleep(0);
+
+ if (testDeviceLost(true))
+ {
+ return;
+ }
+ }
+ while (result == S_FALSE);
+ }
+ else
+ {
+ mDeviceContext->Flush();
+ }
+}
+
+SwapChain *Renderer11::createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat)
+{
+ return new rx::SwapChain11(this, window, shareHandle, backBufferFormat, depthBufferFormat);
+}
+
+void Renderer11::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState)
+{
+ if (type == gl::SAMPLER_PIXEL)
+ {
+ if (index < 0 || index >= gl::MAX_TEXTURE_IMAGE_UNITS)
+ {
+ ERR("Pixel shader sampler index %i is not valid.", index);
+ return;
+ }
+
+ if (mForceSetPixelSamplerStates[index] || memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0)
+ {
+ ID3D11SamplerState *dxSamplerState = mStateCache.getSamplerState(samplerState);
+
+ if (!dxSamplerState)
+ {
+ ERR("NULL sampler state returned by RenderStateCache::getSamplerState, setting the default"
+ "sampler state for pixel shaders at slot %i.", index);
+ }
+
+ mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState);
+
+ mCurPixelSamplerStates[index] = samplerState;
+ }
+
+ mForceSetPixelSamplerStates[index] = false;
+ }
+ else if (type == gl::SAMPLER_VERTEX)
+ {
+ if (index < 0 || index >= (int)getMaxVertexTextureImageUnits())
+ {
+ ERR("Vertex shader sampler index %i is not valid.", index);
+ return;
+ }
+
+ if (mForceSetVertexSamplerStates[index] || memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0)
+ {
+ ID3D11SamplerState *dxSamplerState = mStateCache.getSamplerState(samplerState);
+
+ if (!dxSamplerState)
+ {
+ ERR("NULL sampler state returned by RenderStateCache::getSamplerState, setting the default"
+ "sampler state for vertex shaders at slot %i.", index);
+ }
+
+ mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState);
+
+ mCurVertexSamplerStates[index] = samplerState;
+ }
+
+ mForceSetVertexSamplerStates[index] = false;
+ }
+ else UNREACHABLE();
+}
+
+void Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture)
+{
+ ID3D11ShaderResourceView *textureSRV = NULL;
+ unsigned int serial = 0;
+ bool forceSetTexture = false;
+
+ if (texture)
+ {
+ TextureStorageInterface *texStorage = texture->getNativeTexture();
+ if (texStorage)
+ {
+ TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage->getStorageInstance());
+ textureSRV = storage11->getSRV();
+ }
+
+ // 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);
+
+ serial = texture->getTextureSerial();
+ forceSetTexture = texture->hasDirtyImages();
+ }
+
+ if (type == gl::SAMPLER_PIXEL)
+ {
+ if (index < 0 || index >= gl::MAX_TEXTURE_IMAGE_UNITS)
+ {
+ ERR("Pixel shader sampler index %i is not valid.", index);
+ return;
+ }
+
+ if (forceSetTexture || mCurPixelTextureSerials[index] != serial)
+ {
+ mDeviceContext->PSSetShaderResources(index, 1, &textureSRV);
+ }
+
+ mCurPixelTextureSerials[index] = serial;
+ }
+ else if (type == gl::SAMPLER_VERTEX)
+ {
+ if (index < 0 || index >= (int)getMaxVertexTextureImageUnits())
+ {
+ ERR("Vertex shader sampler index %i is not valid.", index);
+ return;
+ }
+
+ if (forceSetTexture || mCurVertexTextureSerials[index] != serial)
+ {
+ mDeviceContext->VSSetShaderResources(index, 1, &textureSRV);
+ }
+
+ mCurVertexTextureSerials[index] = serial;
+ }
+ else UNREACHABLE();
+}
+
+void Renderer11::setRasterizerState(const gl::RasterizerState &rasterState)
+{
+ if (mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0)
+ {
+ ID3D11RasterizerState *dxRasterState = mStateCache.getRasterizerState(rasterState, mScissorEnabled,
+ mCurDepthSize);
+ if (!dxRasterState)
+ {
+ ERR("NULL rasterizer state returned by RenderStateCache::getRasterizerState, setting the default"
+ "rasterizer state.");
+ }
+
+ mDeviceContext->RSSetState(dxRasterState);
+
+ mCurRasterState = rasterState;
+ }
+
+ mForceSetRasterState = false;
+}
+
+void Renderer11::setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor,
+ unsigned int sampleMask)
+{
+ if (mForceSetBlendState ||
+ memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0 ||
+ memcmp(&blendColor, &mCurBlendColor, sizeof(gl::Color)) != 0 ||
+ sampleMask != mCurSampleMask)
+ {
+ ID3D11BlendState *dxBlendState = mStateCache.getBlendState(blendState);
+ if (!dxBlendState)
+ {
+ ERR("NULL blend state returned by RenderStateCache::getBlendState, setting the default "
+ "blend state.");
+ }
+
+ float blendColors[4] = {0.0f};
+ if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
+ blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
+ {
+ blendColors[0] = blendColor.red;
+ blendColors[1] = blendColor.green;
+ blendColors[2] = blendColor.blue;
+ blendColors[3] = blendColor.alpha;
+ }
+ else
+ {
+ blendColors[0] = blendColor.alpha;
+ blendColors[1] = blendColor.alpha;
+ blendColors[2] = blendColor.alpha;
+ blendColors[3] = blendColor.alpha;
+ }
+
+ mDeviceContext->OMSetBlendState(dxBlendState, blendColors, sampleMask);
+
+ mCurBlendState = blendState;
+ mCurBlendColor = blendColor;
+ mCurSampleMask = sampleMask;
+ }
+
+ mForceSetBlendState = false;
+}
+
+void Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
+ int stencilBackRef, bool frontFaceCCW)
+{
+ if (mForceSetDepthStencilState ||
+ memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0 ||
+ stencilRef != mCurStencilRef || stencilBackRef != mCurStencilBackRef)
+ {
+ if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
+ stencilRef != stencilBackRef ||
+ depthStencilState.stencilMask != depthStencilState.stencilBackMask)
+ {
+ ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are "
+ "invalid under WebGL.");
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ ID3D11DepthStencilState *dxDepthStencilState = mStateCache.getDepthStencilState(depthStencilState);
+ if (!dxDepthStencilState)
+ {
+ ERR("NULL depth stencil state returned by RenderStateCache::getDepthStencilState, "
+ "setting the default depth stencil state.");
+ }
+
+ mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, static_cast<UINT>(stencilRef));
+
+ mCurDepthStencilState = depthStencilState;
+ mCurStencilRef = stencilRef;
+ mCurStencilBackRef = stencilBackRef;
+ }
+
+ mForceSetDepthStencilState = false;
+}
+
+void Renderer11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled)
+{
+ if (mForceSetScissor || memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 ||
+ enabled != mScissorEnabled)
+ {
+ if (enabled)
+ {
+ D3D11_RECT rect;
+ rect.left = std::max(0, scissor.x);
+ rect.top = std::max(0, scissor.y);
+ rect.right = scissor.x + std::max(0, scissor.width);
+ rect.bottom = scissor.y + std::max(0, scissor.height);
+
+ mDeviceContext->RSSetScissorRects(1, &rect);
+ }
+
+ if (enabled != mScissorEnabled)
+ {
+ mForceSetRasterState = true;
+ }
+
+ mCurScissor = scissor;
+ mScissorEnabled = enabled;
+ }
+
+ mForceSetScissor = false;
+}
+
+bool Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
+ bool ignoreViewport)
+{
+ gl::Rectangle actualViewport = viewport;
+ float actualZNear = gl::clamp01(zNear);
+ float actualZFar = gl::clamp01(zFar);
+ if (ignoreViewport)
+ {
+ actualViewport.x = 0;
+ actualViewport.y = 0;
+ actualViewport.width = mRenderTargetDesc.width;
+ actualViewport.height = mRenderTargetDesc.height;
+ actualZNear = 0.0f;
+ actualZFar = 1.0f;
+ }
+
+ // Get D3D viewport bounds, which depends on the feature level
+ const Range& viewportBounds = getViewportBounds();
+
+ // Clamp width and height first to the gl maximum, then clamp further if we extend past the D3D maximum bounds
+ D3D11_VIEWPORT dxViewport;
+ dxViewport.TopLeftX = gl::clamp(actualViewport.x, viewportBounds.start, viewportBounds.end);
+ dxViewport.TopLeftY = gl::clamp(actualViewport.y, viewportBounds.start, viewportBounds.end);
+ dxViewport.Width = gl::clamp(actualViewport.width, 0, getMaxViewportDimension());
+ dxViewport.Height = gl::clamp(actualViewport.height, 0, getMaxViewportDimension());
+ dxViewport.Width = std::min((int)dxViewport.Width, viewportBounds.end - static_cast<int>(dxViewport.TopLeftX));
+ dxViewport.Height = std::min((int)dxViewport.Height, viewportBounds.end - static_cast<int>(dxViewport.TopLeftY));
+ dxViewport.MinDepth = actualZNear;
+ dxViewport.MaxDepth = actualZFar;
+
+ if (dxViewport.Width <= 0 || dxViewport.Height <= 0)
+ {
+ return false; // Nothing to render
+ }
+
+ bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 ||
+ actualZNear != mCurNear || actualZFar != mCurFar;
+
+ if (viewportChanged)
+ {
+ mDeviceContext->RSSetViewports(1, &dxViewport);
+
+ mCurViewport = actualViewport;
+ mCurNear = actualZNear;
+ mCurFar = actualZFar;
+
+ mPixelConstants.viewCoords[0] = actualViewport.width * 0.5f;
+ mPixelConstants.viewCoords[1] = actualViewport.height * 0.5f;
+ mPixelConstants.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f);
+ mPixelConstants.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f);
+
+ mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f;
+ mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f;
+
+ mVertexConstants.depthRange[0] = actualZNear;
+ mVertexConstants.depthRange[1] = actualZFar;
+ mVertexConstants.depthRange[2] = actualZFar - actualZNear;
+
+ mPixelConstants.depthRange[0] = actualZNear;
+ mPixelConstants.depthRange[1] = actualZFar;
+ mPixelConstants.depthRange[2] = actualZFar - actualZNear;
+ }
+
+ mForceSetViewport = false;
+ return true;
+}
+
+bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count)
+{
+ 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:
+ return gl::error(GL_INVALID_ENUM, false);
+ }
+
+ if (primitiveTopology != mCurrentPrimitiveTopology)
+ {
+ mDeviceContext->IASetPrimitiveTopology(primitiveTopology);
+ mCurrentPrimitiveTopology = primitiveTopology;
+ }
+
+ return count >= minCount;
+}
+
+bool Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer)
+{
+ // Get the color render buffer and serial
+ // Also extract the render target dimensions and view
+ unsigned int renderTargetWidth = 0;
+ unsigned int renderTargetHeight = 0;
+ GLenum renderTargetFormat = 0;
+ unsigned int renderTargetSerials[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {0};
+ ID3D11RenderTargetView* framebufferRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL};
+ bool missingColorRenderTarget = true;
+
+ for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ const GLenum drawBufferState = framebuffer->getDrawBufferState(colorAttachment);
+
+ if (framebuffer->getColorbufferType(colorAttachment) != GL_NONE && drawBufferState != GL_NONE)
+ {
+ // the draw buffer must be either "none", "back" for the default buffer or the same index as this color (in order)
+ ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment));
+
+ gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(colorAttachment);
+
+ if (!colorbuffer)
+ {
+ ERR("render target pointer unexpectedly null.");
+ return false;
+ }
+
+ // check for zero-sized default framebuffer, which is a special case.
+ // in this case we do not wish to modify any state and just silently return false.
+ // this will not report any gl error but will cause the calling method to return.
+ if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
+ {
+ return false;
+ }
+
+ renderTargetSerials[colorAttachment] = colorbuffer->getSerial();
+
+ // Extract the render target dimensions and view
+ RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget());
+ if (!renderTarget)
+ {
+ ERR("render target pointer unexpectedly null.");
+ return false;
+ }
+
+ framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView();
+ if (!framebufferRTVs[colorAttachment])
+ {
+ ERR("render target view pointer unexpectedly null.");
+ return false;
+ }
+
+ if (missingColorRenderTarget)
+ {
+ renderTargetWidth = colorbuffer->getWidth();
+ renderTargetHeight = colorbuffer->getHeight();
+ renderTargetFormat = colorbuffer->getActualFormat();
+ missingColorRenderTarget = false;
+ }
+ }
+ }
+
+ // Get the depth stencil render buffer and serials
+ gl::Renderbuffer *depthStencil = NULL;
+ unsigned int depthbufferSerial = 0;
+ unsigned int stencilbufferSerial = 0;
+ if (framebuffer->getDepthbufferType() != GL_NONE)
+ {
+ depthStencil = framebuffer->getDepthbuffer();
+ if (!depthStencil)
+ {
+ ERR("Depth stencil pointer unexpectedly null.");
+ SafeRelease(framebufferRTVs);
+ return false;
+ }
+
+ depthbufferSerial = depthStencil->getSerial();
+ }
+ else if (framebuffer->getStencilbufferType() != GL_NONE)
+ {
+ depthStencil = framebuffer->getStencilbuffer();
+ if (!depthStencil)
+ {
+ ERR("Depth stencil pointer unexpectedly null.");
+ SafeRelease(framebufferRTVs);
+ return false;
+ }
+
+ stencilbufferSerial = depthStencil->getSerial();
+ }
+
+ // Extract the depth stencil sizes and view
+ unsigned int depthSize = 0;
+ unsigned int stencilSize = 0;
+ ID3D11DepthStencilView* framebufferDSV = NULL;
+ if (depthStencil)
+ {
+ RenderTarget11 *depthStencilRenderTarget = RenderTarget11::makeRenderTarget11(depthStencil->getDepthStencil());
+ if (!depthStencilRenderTarget)
+ {
+ ERR("render target pointer unexpectedly null.");
+ SafeRelease(framebufferRTVs);
+ return false;
+ }
+
+ framebufferDSV = depthStencilRenderTarget->getDepthStencilView();
+ if (!framebufferDSV)
+ {
+ ERR("depth stencil view pointer unexpectedly null.");
+ SafeRelease(framebufferRTVs);
+ return false;
+ }
+
+ // If there is no render buffer, the width, height and format values come from
+ // the depth stencil
+ if (missingColorRenderTarget)
+ {
+ renderTargetWidth = depthStencil->getWidth();
+ renderTargetHeight = depthStencil->getHeight();
+ renderTargetFormat = depthStencil->getActualFormat();
+ }
+
+ depthSize = depthStencil->getDepthSize();
+ stencilSize = depthStencil->getStencilSize();
+ }
+
+ // Apply the render target and depth stencil
+ if (!mRenderTargetDescInitialized || !mDepthStencilInitialized ||
+ memcmp(renderTargetSerials, mAppliedRenderTargetSerials, sizeof(renderTargetSerials)) != 0 ||
+ depthbufferSerial != mAppliedDepthbufferSerial ||
+ stencilbufferSerial != mAppliedStencilbufferSerial)
+ {
+ mDeviceContext->OMSetRenderTargets(getMaxRenderTargets(), framebufferRTVs, framebufferDSV);
+
+ mRenderTargetDesc.width = renderTargetWidth;
+ mRenderTargetDesc.height = renderTargetHeight;
+ mRenderTargetDesc.format = renderTargetFormat;
+ mForceSetViewport = true;
+ mForceSetScissor = true;
+
+ if (!mDepthStencilInitialized || depthSize != mCurDepthSize)
+ {
+ mCurDepthSize = depthSize;
+ mForceSetRasterState = true;
+ }
+
+ mCurStencilSize = stencilSize;
+
+ for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++)
+ {
+ mAppliedRenderTargetSerials[rtIndex] = renderTargetSerials[rtIndex];
+ }
+ mAppliedDepthbufferSerial = depthbufferSerial;
+ mAppliedStencilbufferSerial = stencilbufferSerial;
+ mRenderTargetDescInitialized = true;
+ mDepthStencilInitialized = true;
+ }
+
+ return true;
+}
+
+GLenum Renderer11::applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances)
+{
+ TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS];
+ GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, programBinary, first, count, attributes, instances);
+ if (err != GL_NO_ERROR)
+ {
+ return err;
+ }
+
+ return mInputLayoutCache.applyVertexBuffers(attributes, programBinary);
+}
+
+GLenum Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
+{
+ GLenum err = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo);
+
+ if (err == GL_NO_ERROR)
+ {
+ if (indexInfo->storage)
+ {
+ if (indexInfo->serial != mAppliedStorageIBSerial || indexInfo->startOffset != mAppliedIBOffset)
+ {
+ BufferStorage11 *storage = BufferStorage11::makeBufferStorage11(indexInfo->storage);
+ IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer);
+
+ mDeviceContext->IASetIndexBuffer(storage->getBuffer(), indexBuffer->getIndexFormat(), indexInfo->startOffset);
+
+ mAppliedIBSerial = 0;
+ mAppliedStorageIBSerial = storage->getSerial();
+ mAppliedIBOffset = indexInfo->startOffset;
+ }
+ }
+ else if (indexInfo->serial != mAppliedIBSerial || indexInfo->startOffset != mAppliedIBOffset)
+ {
+ IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer);
+
+ mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexInfo->startOffset);
+
+ mAppliedIBSerial = indexInfo->serial;
+ mAppliedStorageIBSerial = 0;
+ mAppliedIBOffset = indexInfo->startOffset;
+ }
+ }
+
+ return err;
+}
+
+void Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances)
+{
+ if (mode == GL_LINE_LOOP)
+ {
+ drawLineLoop(count, GL_NONE, NULL, 0, NULL);
+ }
+ else if (mode == GL_TRIANGLE_FAN)
+ {
+ drawTriangleFan(count, GL_NONE, NULL, 0, NULL, instances);
+ }
+ else if (instances > 0)
+ {
+ mDeviceContext->DrawInstanced(count, instances, 0, 0);
+ }
+ else
+ {
+ mDeviceContext->Draw(count, 0);
+ }
+}
+
+void Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances)
+{
+ if (mode == GL_LINE_LOOP)
+ {
+ drawLineLoop(count, type, indices, indexInfo.minIndex, elementArrayBuffer);
+ }
+ else if (mode == GL_TRIANGLE_FAN)
+ {
+ drawTriangleFan(count, type, indices, indexInfo.minIndex, elementArrayBuffer, instances);
+ }
+ else if (instances > 0)
+ {
+ mDeviceContext->DrawIndexedInstanced(count, instances, 0, -static_cast<int>(indexInfo.minIndex), 0);
+ }
+ else
+ {
+ mDeviceContext->DrawIndexed(count, 0, -static_cast<int>(indexInfo.minIndex));
+ }
+}
+
+void Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer)
+{
+ // Get the raw indices for an indexed draw
+ if (type != GL_NONE && elementArrayBuffer)
+ {
+ gl::Buffer *indexBuffer = elementArrayBuffer;
+ BufferStorage *storage = indexBuffer->getStorage();
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ indices = static_cast<const GLubyte*>(storage->getData()) + offset;
+ }
+
+ if (!mLineLoopIB)
+ {
+ mLineLoopIB = new StreamingIndexBufferInterface(this);
+ if (!mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
+ {
+ delete mLineLoopIB;
+ mLineLoopIB = NULL;
+
+ ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ // Checked by Renderer11::applyPrimitiveType
+ ASSERT(count >= 0);
+
+ if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int)))
+ {
+ ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int);
+ if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT))
+ {
+ ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ void* mappedMemory = NULL;
+ int offset = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory);
+ if (offset == -1 || mappedMemory == NULL)
+ {
+ ERR("Could not map index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
+ unsigned int indexBufferOffset = static_cast<unsigned int>(offset);
+
+ switch (type)
+ {
+ case GL_NONE: // Non-indexed draw
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = i;
+ }
+ data[count] = 0;
+ break;
+ case GL_UNSIGNED_BYTE:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLubyte*>(indices)[i];
+ }
+ data[count] = static_cast<const GLubyte*>(indices)[0];
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLushort*>(indices)[i];
+ }
+ data[count] = static_cast<const GLushort*>(indices)[0];
+ break;
+ case GL_UNSIGNED_INT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLuint*>(indices)[i];
+ }
+ data[count] = static_cast<const GLuint*>(indices)[0];
+ break;
+ default: UNREACHABLE();
+ }
+
+ if (!mLineLoopIB->unmapBuffer())
+ {
+ ERR("Could not unmap index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ if (mAppliedIBSerial != mLineLoopIB->getSerial() || mAppliedIBOffset != indexBufferOffset)
+ {
+ IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer());
+
+ mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexBufferOffset);
+ mAppliedIBSerial = mLineLoopIB->getSerial();
+ mAppliedStorageIBSerial = 0;
+ mAppliedIBOffset = indexBufferOffset;
+ }
+
+ mDeviceContext->DrawIndexed(count + 1, 0, -minIndex);
+}
+
+void Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances)
+{
+ // Get the raw indices for an indexed draw
+ if (type != GL_NONE && elementArrayBuffer)
+ {
+ gl::Buffer *indexBuffer = elementArrayBuffer;
+ BufferStorage *storage = indexBuffer->getStorage();
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ indices = static_cast<const GLubyte*>(storage->getData()) + offset;
+ }
+
+ if (!mTriangleFanIB)
+ {
+ mTriangleFanIB = new StreamingIndexBufferInterface(this);
+ if (!mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
+ {
+ delete mTriangleFanIB;
+ mTriangleFanIB = NULL;
+
+ ERR("Could not create a scratch index buffer for GL_TRIANGLE_FAN.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ // Checked by Renderer11::applyPrimitiveType
+ ASSERT(count >= 3);
+
+ const unsigned int numTris = count - 2;
+
+ if (numTris > (std::numeric_limits<unsigned int>::max() / (sizeof(unsigned int) * 3)))
+ {
+ ERR("Could not create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ const unsigned int spaceNeeded = (numTris * 3) * sizeof(unsigned int);
+ if (!mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT))
+ {
+ ERR("Could not reserve enough space in scratch index buffer for GL_TRIANGLE_FAN.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ void* mappedMemory = NULL;
+ int offset = mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory);
+ if (offset == -1 || mappedMemory == NULL)
+ {
+ ERR("Could not map scratch index buffer for GL_TRIANGLE_FAN.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
+ unsigned int indexBufferOffset = static_cast<unsigned int>(offset);
+
+ switch (type)
+ {
+ case GL_NONE: // Non-indexed draw
+ for (unsigned int i = 0; i < numTris; i++)
+ {
+ data[i*3 + 0] = 0;
+ data[i*3 + 1] = i + 1;
+ data[i*3 + 2] = i + 2;
+ }
+ break;
+ case GL_UNSIGNED_BYTE:
+ for (unsigned int i = 0; i < numTris; i++)
+ {
+ data[i*3 + 0] = static_cast<const GLubyte*>(indices)[0];
+ data[i*3 + 1] = static_cast<const GLubyte*>(indices)[i + 1];
+ data[i*3 + 2] = static_cast<const GLubyte*>(indices)[i + 2];
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (unsigned int i = 0; i < numTris; i++)
+ {
+ data[i*3 + 0] = static_cast<const GLushort*>(indices)[0];
+ data[i*3 + 1] = static_cast<const GLushort*>(indices)[i + 1];
+ data[i*3 + 2] = static_cast<const GLushort*>(indices)[i + 2];
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ for (unsigned int i = 0; i < numTris; i++)
+ {
+ data[i*3 + 0] = static_cast<const GLuint*>(indices)[0];
+ data[i*3 + 1] = static_cast<const GLuint*>(indices)[i + 1];
+ data[i*3 + 2] = static_cast<const GLuint*>(indices)[i + 2];
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ if (!mTriangleFanIB->unmapBuffer())
+ {
+ ERR("Could not unmap scratch index buffer for GL_TRIANGLE_FAN.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ if (mAppliedIBSerial != mTriangleFanIB->getSerial() || mAppliedIBOffset != indexBufferOffset)
+ {
+ IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer());
+
+ mDeviceContext->IASetIndexBuffer(indexBuffer->getBuffer(), indexBuffer->getIndexFormat(), indexBufferOffset);
+ mAppliedIBSerial = mTriangleFanIB->getSerial();
+ mAppliedStorageIBSerial = 0;
+ mAppliedIBOffset = indexBufferOffset;
+ }
+
+ if (instances > 0)
+ {
+ mDeviceContext->DrawIndexedInstanced(numTris * 3, instances, 0, -minIndex, 0);
+ }
+ else
+ {
+ mDeviceContext->DrawIndexed(numTris * 3, 0, -minIndex);
+ }
+}
+
+void Renderer11::applyShaders(gl::ProgramBinary *programBinary)
+{
+ unsigned int programBinarySerial = programBinary->getSerial();
+ const bool updateProgramState = (programBinarySerial != mAppliedProgramBinarySerial);
+
+ if (updateProgramState)
+ {
+ ShaderExecutable *vertexExe = programBinary->getVertexExecutable();
+ ShaderExecutable *pixelExe = programBinary->getPixelExecutable();
+
+ ID3D11VertexShader *vertexShader = NULL;
+ if (vertexExe) vertexShader = ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader();
+
+ ID3D11PixelShader *pixelShader = NULL;
+ if (pixelExe) pixelShader = ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader();
+
+ mDeviceContext->PSSetShader(pixelShader, NULL, 0);
+ mDeviceContext->VSSetShader(vertexShader, NULL, 0);
+
+ programBinary->dirtyAllUniforms();
+
+ mAppliedProgramBinarySerial = programBinarySerial;
+ }
+
+ // Only use the geometry shader currently for point sprite drawing
+ const bool usesGeometryShader = (programBinary->usesGeometryShader() && mCurRasterState.pointDrawMode);
+
+ if (updateProgramState || usesGeometryShader != mIsGeometryShaderActive)
+ {
+ if (usesGeometryShader)
+ {
+ ShaderExecutable *geometryExe = programBinary->getGeometryExecutable();
+ ID3D11GeometryShader *geometryShader = ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader();
+ mDeviceContext->GSSetShader(geometryShader, NULL, 0);
+ }
+ else
+ {
+ mDeviceContext->GSSetShader(NULL, NULL, 0);
+ }
+
+ mIsGeometryShaderActive = usesGeometryShader;
+ }
+}
+
+void Renderer11::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray)
+{
+ ShaderExecutable11 *vertexExecutable = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutable());
+ ShaderExecutable11 *pixelExecutable = ShaderExecutable11::makeShaderExecutable11(programBinary->getPixelExecutable());
+
+ unsigned int totalRegisterCountVS = 0;
+ unsigned int totalRegisterCountPS = 0;
+
+ bool vertexUniformsDirty = false;
+ bool pixelUniformsDirty = false;
+
+ for (gl::UniformArray::const_iterator uniform_iterator = uniformArray->begin(); uniform_iterator != uniformArray->end(); uniform_iterator++)
+ {
+ const gl::Uniform *uniform = *uniform_iterator;
+
+ if (uniform->vsRegisterIndex >= 0)
+ {
+ totalRegisterCountVS += uniform->registerCount;
+ vertexUniformsDirty = vertexUniformsDirty || uniform->dirty;
+ }
+
+ if (uniform->psRegisterIndex >= 0)
+ {
+ totalRegisterCountPS += uniform->registerCount;
+ pixelUniformsDirty = pixelUniformsDirty || uniform->dirty;
+ }
+ }
+
+ ID3D11Buffer *vertexConstantBuffer = vertexExecutable->getConstantBuffer(mDevice, totalRegisterCountVS);
+ ID3D11Buffer *pixelConstantBuffer = pixelExecutable->getConstantBuffer(mDevice, totalRegisterCountPS);
+
+ float (*mapVS)[4] = NULL;
+ float (*mapPS)[4] = NULL;
+
+ if (totalRegisterCountVS > 0 && vertexUniformsDirty)
+ {
+ D3D11_MAPPED_SUBRESOURCE map = {0};
+ HRESULT result = mDeviceContext->Map(vertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
+ ASSERT(SUCCEEDED(result));
+ mapVS = (float(*)[4])map.pData;
+ }
+
+ if (totalRegisterCountPS > 0 && pixelUniformsDirty)
+ {
+ D3D11_MAPPED_SUBRESOURCE map = {0};
+ HRESULT result = mDeviceContext->Map(pixelConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
+ ASSERT(SUCCEEDED(result));
+ mapPS = (float(*)[4])map.pData;
+ }
+
+ for (gl::UniformArray::iterator uniform_iterator = uniformArray->begin(); uniform_iterator != uniformArray->end(); uniform_iterator++)
+ {
+ gl::Uniform *uniform = *uniform_iterator;
+
+ if (uniform->type != GL_SAMPLER_2D && uniform->type != GL_SAMPLER_CUBE)
+ {
+ if (uniform->vsRegisterIndex >= 0 && mapVS)
+ {
+ memcpy(mapVS + uniform->vsRegisterIndex, uniform->data, uniform->registerCount * sizeof(float[4]));
+ }
+
+ if (uniform->psRegisterIndex >= 0 && mapPS)
+ {
+ memcpy(mapPS + uniform->psRegisterIndex, uniform->data, uniform->registerCount * sizeof(float[4]));
+ }
+ }
+
+ uniform->dirty = false;
+ }
+
+ if (mapVS)
+ {
+ mDeviceContext->Unmap(vertexConstantBuffer, 0);
+ }
+
+ if (mapPS)
+ {
+ mDeviceContext->Unmap(pixelConstantBuffer, 0);
+ }
+
+ if (mCurrentVertexConstantBuffer != vertexConstantBuffer)
+ {
+ mDeviceContext->VSSetConstantBuffers(0, 1, &vertexConstantBuffer);
+ mCurrentVertexConstantBuffer = vertexConstantBuffer;
+ }
+
+ if (mCurrentPixelConstantBuffer != pixelConstantBuffer)
+ {
+ mDeviceContext->PSSetConstantBuffers(0, 1, &pixelConstantBuffer);
+ mCurrentPixelConstantBuffer = pixelConstantBuffer;
+ }
+
+ // Driver uniforms
+ if (!mDriverConstantBufferVS)
+ {
+ D3D11_BUFFER_DESC constantBufferDescription = {0};
+ constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants);
+ constantBufferDescription.Usage = D3D11_USAGE_DEFAULT;
+ constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ constantBufferDescription.CPUAccessFlags = 0;
+ constantBufferDescription.MiscFlags = 0;
+ constantBufferDescription.StructureByteStride = 0;
+
+ HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS);
+ ASSERT(SUCCEEDED(result));
+
+ mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS);
+ }
+
+ if (!mDriverConstantBufferPS)
+ {
+ D3D11_BUFFER_DESC constantBufferDescription = {0};
+ constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants);
+ constantBufferDescription.Usage = D3D11_USAGE_DEFAULT;
+ constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ constantBufferDescription.CPUAccessFlags = 0;
+ constantBufferDescription.MiscFlags = 0;
+ constantBufferDescription.StructureByteStride = 0;
+
+ HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS);
+ ASSERT(SUCCEEDED(result));
+
+ mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS);
+ }
+
+ if (memcmp(&mVertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants)) != 0)
+ {
+ mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &mVertexConstants, 16, 0);
+ memcpy(&mAppliedVertexConstants, &mVertexConstants, sizeof(dx_VertexConstants));
+ }
+
+ if (memcmp(&mPixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants)) != 0)
+ {
+ mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &mPixelConstants, 16, 0);
+ memcpy(&mAppliedPixelConstants, &mPixelConstants, sizeof(dx_PixelConstants));
+ }
+
+ // needed for the point sprite geometry shader
+ if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS)
+ {
+ mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS);
+ mCurrentGeometryConstantBuffer = mDriverConstantBufferPS;
+ }
+}
+
+void Renderer11::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer)
+{
+ bool alphaUnmasked = (gl::GetAlphaSize(mRenderTargetDesc.format) == 0) || clearParams.colorMaskAlpha;
+ bool needMaskedColorClear = (clearParams.mask & GL_COLOR_BUFFER_BIT) &&
+ !(clearParams.colorMaskRed && clearParams.colorMaskGreen &&
+ clearParams.colorMaskBlue && alphaUnmasked);
+
+ unsigned int stencilUnmasked = 0x0;
+ if (frameBuffer->hasStencil())
+ {
+ unsigned int stencilSize = gl::GetStencilSize(frameBuffer->getStencilbuffer()->getActualFormat());
+ stencilUnmasked = (0x1 << stencilSize) - 1;
+ }
+ bool needMaskedStencilClear = (clearParams.mask & GL_STENCIL_BUFFER_BIT) &&
+ (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
+
+ bool needScissoredClear = mScissorEnabled && (mCurScissor.x > 0 || mCurScissor.y > 0 ||
+ mCurScissor.x + mCurScissor.width < mRenderTargetDesc.width ||
+ mCurScissor.y + mCurScissor.height < mRenderTargetDesc.height);
+
+ if (needMaskedColorClear || needMaskedStencilClear || needScissoredClear)
+ {
+ maskedClear(clearParams, frameBuffer->usingExtendedDrawBuffers());
+ }
+ else
+ {
+ if (clearParams.mask & GL_COLOR_BUFFER_BIT)
+ {
+ for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (frameBuffer->isEnabledColorAttachment(colorAttachment))
+ {
+ gl::Renderbuffer *renderbufferObject = frameBuffer->getColorbuffer(colorAttachment);
+ if (renderbufferObject)
+ {
+ RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbufferObject->getRenderTarget());
+ if (!renderTarget)
+ {
+ ERR("render target pointer unexpectedly null.");
+ return;
+ }
+
+ ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView();
+ if (!framebufferRTV)
+ {
+ ERR("render target view pointer unexpectedly null.");
+ return;
+ }
+
+ const float clearValues[4] = { clearParams.colorClearValue.red,
+ clearParams.colorClearValue.green,
+ clearParams.colorClearValue.blue,
+ clearParams.colorClearValue.alpha };
+ mDeviceContext->ClearRenderTargetView(framebufferRTV, clearValues);
+ }
+ }
+ }
+ }
+ if (clearParams.mask & GL_DEPTH_BUFFER_BIT || clearParams.mask & GL_STENCIL_BUFFER_BIT)
+ {
+ gl::Renderbuffer *renderbufferObject = frameBuffer->getDepthOrStencilbuffer();
+ if (renderbufferObject)
+ {
+ RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(renderbufferObject->getDepthStencil());
+ if (!renderTarget)
+ {
+ ERR("render target pointer unexpectedly null.");
+ return;
+ }
+
+ ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView();
+ if (!framebufferDSV)
+ {
+ ERR("depth stencil view pointer unexpectedly null.");
+ return;
+ }
+
+ UINT clearFlags = 0;
+ if (clearParams.mask & GL_DEPTH_BUFFER_BIT)
+ {
+ clearFlags |= D3D11_CLEAR_DEPTH;
+ }
+ if (clearParams.mask & GL_STENCIL_BUFFER_BIT)
+ {
+ clearFlags |= D3D11_CLEAR_STENCIL;
+ }
+
+ float depthClear = gl::clamp01(clearParams.depthClearValue);
+ UINT8 stencilClear = clearParams.stencilClearValue & 0x000000FF;
+
+ mDeviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear);
+ }
+ }
+ }
+}
+
+void Renderer11::maskedClear(const gl::ClearParameters &clearParams, bool usingExtendedDrawBuffers)
+{
+ HRESULT result;
+
+ if (!mClearResourcesInitialized)
+ {
+ ASSERT(!mClearVB && !mClearVS && !mClearSinglePS && !mClearMultiplePS && !mClearScissorRS && !mClearNoScissorRS);
+
+ D3D11_BUFFER_DESC vbDesc;
+ vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex) * 4;
+ vbDesc.Usage = D3D11_USAGE_DYNAMIC;
+ vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ vbDesc.MiscFlags = 0;
+ vbDesc.StructureByteStride = 0;
+
+ result = mDevice->CreateBuffer(&vbDesc, NULL, &mClearVB);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mClearVB, "Renderer11 masked clear vertex buffer");
+
+ D3D11_INPUT_ELEMENT_DESC quadLayout[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+
+ result = mDevice->CreateInputLayout(quadLayout, 2, g_VS_Clear, sizeof(g_VS_Clear), &mClearIL);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mClearIL, "Renderer11 masked clear input layout");
+
+ result = mDevice->CreateVertexShader(g_VS_Clear, sizeof(g_VS_Clear), NULL, &mClearVS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mClearVS, "Renderer11 masked clear vertex shader");
+
+ result = mDevice->CreatePixelShader(g_PS_ClearSingle, sizeof(g_PS_ClearSingle), NULL, &mClearSinglePS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mClearSinglePS, "Renderer11 masked clear pixel shader (1 RT)");
+
+ result = mDevice->CreatePixelShader(g_PS_ClearMultiple, sizeof(g_PS_ClearMultiple), NULL, &mClearMultiplePS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mClearMultiplePS, "Renderer11 masked clear pixel shader (MRT)");
+
+ D3D11_RASTERIZER_DESC rsScissorDesc;
+ rsScissorDesc.FillMode = D3D11_FILL_SOLID;
+ rsScissorDesc.CullMode = D3D11_CULL_NONE;
+ rsScissorDesc.FrontCounterClockwise = FALSE;
+ rsScissorDesc.DepthBias = 0;
+ rsScissorDesc.DepthBiasClamp = 0.0f;
+ rsScissorDesc.SlopeScaledDepthBias = 0.0f;
+ rsScissorDesc.DepthClipEnable = FALSE;
+ rsScissorDesc.ScissorEnable = TRUE;
+ rsScissorDesc.MultisampleEnable = FALSE;
+ rsScissorDesc.AntialiasedLineEnable = FALSE;
+
+ result = mDevice->CreateRasterizerState(&rsScissorDesc, &mClearScissorRS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mClearScissorRS, "Renderer11 masked clear scissor rasterizer state");
+
+ D3D11_RASTERIZER_DESC rsNoScissorDesc;
+ rsNoScissorDesc.FillMode = D3D11_FILL_SOLID;
+ rsNoScissorDesc.CullMode = D3D11_CULL_NONE;
+ rsNoScissorDesc.FrontCounterClockwise = FALSE;
+ rsNoScissorDesc.DepthBias = 0;
+ rsNoScissorDesc.DepthBiasClamp = 0.0f;
+ rsNoScissorDesc.SlopeScaledDepthBias = 0.0f;
+ rsNoScissorDesc.DepthClipEnable = FALSE;
+ rsNoScissorDesc.ScissorEnable = FALSE;
+ rsNoScissorDesc.MultisampleEnable = FALSE;
+ rsNoScissorDesc.AntialiasedLineEnable = FALSE;
+
+ result = mDevice->CreateRasterizerState(&rsNoScissorDesc, &mClearNoScissorRS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mClearNoScissorRS, "Renderer11 masked clear no scissor rasterizer state");
+
+ mClearResourcesInitialized = true;
+ }
+
+ // Prepare the depth stencil state to write depth values if the depth should be cleared
+ // and stencil values if the stencil should be cleared
+ gl::DepthStencilState glDSState;
+ glDSState.depthTest = (clearParams.mask & GL_DEPTH_BUFFER_BIT) != 0;
+ glDSState.depthFunc = GL_ALWAYS;
+ glDSState.depthMask = (clearParams.mask & GL_DEPTH_BUFFER_BIT) != 0;
+ glDSState.stencilTest = (clearParams.mask & GL_STENCIL_BUFFER_BIT) != 0;
+ glDSState.stencilFunc = GL_ALWAYS;
+ glDSState.stencilMask = 0;
+ glDSState.stencilFail = GL_REPLACE;
+ glDSState.stencilPassDepthFail = GL_REPLACE;
+ glDSState.stencilPassDepthPass = GL_REPLACE;
+ glDSState.stencilWritemask = clearParams.stencilWriteMask;
+ glDSState.stencilBackFunc = GL_ALWAYS;
+ glDSState.stencilBackMask = 0;
+ glDSState.stencilBackFail = GL_REPLACE;
+ glDSState.stencilBackPassDepthFail = GL_REPLACE;
+ glDSState.stencilBackPassDepthPass = GL_REPLACE;
+ glDSState.stencilBackWritemask = clearParams.stencilWriteMask;
+
+ int stencilClear = clearParams.stencilClearValue & 0x000000FF;
+
+ ID3D11DepthStencilState *dsState = mStateCache.getDepthStencilState(glDSState);
+
+ // Prepare the blend state to use a write mask if the color buffer should be cleared
+ gl::BlendState glBlendState;
+ glBlendState.blend = false;
+ glBlendState.sourceBlendRGB = GL_ONE;
+ glBlendState.destBlendRGB = GL_ZERO;
+ glBlendState.sourceBlendAlpha = GL_ONE;
+ glBlendState.destBlendAlpha = GL_ZERO;
+ glBlendState.blendEquationRGB = GL_FUNC_ADD;
+ glBlendState.blendEquationAlpha = GL_FUNC_ADD;
+ glBlendState.colorMaskRed = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskRed : false;
+ glBlendState.colorMaskGreen = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskGreen : false;
+ glBlendState.colorMaskBlue = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskBlue : false;
+ glBlendState.colorMaskAlpha = (clearParams.mask & GL_COLOR_BUFFER_BIT) ? clearParams.colorMaskAlpha : false;
+ glBlendState.sampleAlphaToCoverage = false;
+ glBlendState.dither = false;
+
+ static const float blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ static const UINT sampleMask = 0xFFFFFFFF;
+
+ ID3D11BlendState *blendState = mStateCache.getBlendState(glBlendState);
+
+ // Set the vertices
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ result = mDeviceContext->Map(mClearVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ ERR("Failed to map masked clear vertex buffer, HRESULT: 0x%X.", result);
+ return;
+ }
+
+ d3d11::PositionDepthColorVertex *vertices = reinterpret_cast<d3d11::PositionDepthColorVertex*>(mappedResource.pData);
+
+ float depthClear = gl::clamp01(clearParams.depthClearValue);
+ d3d11::SetPositionDepthColorVertex(&vertices[0], -1.0f, 1.0f, depthClear, clearParams.colorClearValue);
+ d3d11::SetPositionDepthColorVertex(&vertices[1], -1.0f, -1.0f, depthClear, clearParams.colorClearValue);
+ d3d11::SetPositionDepthColorVertex(&vertices[2], 1.0f, 1.0f, depthClear, clearParams.colorClearValue);
+ d3d11::SetPositionDepthColorVertex(&vertices[3], 1.0f, -1.0f, depthClear, clearParams.colorClearValue);
+
+ mDeviceContext->Unmap(mClearVB, 0);
+
+ // Apply state
+ mDeviceContext->OMSetBlendState(blendState, blendFactors, sampleMask);
+ mDeviceContext->OMSetDepthStencilState(dsState, stencilClear);
+ mDeviceContext->RSSetState(mScissorEnabled ? mClearScissorRS : mClearNoScissorRS);
+
+ // Apply shaders
+ ID3D11PixelShader *pixelShader = usingExtendedDrawBuffers ? mClearMultiplePS : mClearSinglePS;
+
+ mDeviceContext->IASetInputLayout(mClearIL);
+ mDeviceContext->VSSetShader(mClearVS, NULL, 0);
+ mDeviceContext->PSSetShader(pixelShader, NULL, 0);
+ mDeviceContext->GSSetShader(NULL, NULL, 0);
+
+ // Apply vertex buffer
+ static UINT stride = sizeof(d3d11::PositionDepthColorVertex);
+ static UINT startIdx = 0;
+ mDeviceContext->IASetVertexBuffers(0, 1, &mClearVB, &stride, &startIdx);
+ mDeviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+
+ // Draw the clear quad
+ mDeviceContext->Draw(4, 0);
+
+ // Clean up
+ markAllStateDirty();
+}
+
+void Renderer11::markAllStateDirty()
+{
+ for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++)
+ {
+ mAppliedRenderTargetSerials[rtIndex] = 0;
+ }
+ mAppliedDepthbufferSerial = 0;
+ mAppliedStencilbufferSerial = 0;
+ mDepthStencilInitialized = false;
+ mRenderTargetDescInitialized = false;
+
+ for (int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++)
+ {
+ mForceSetVertexSamplerStates[i] = true;
+ mCurVertexTextureSerials[i] = 0;
+ }
+ for (int i = 0; i < gl::MAX_TEXTURE_IMAGE_UNITS; i++)
+ {
+ mForceSetPixelSamplerStates[i] = true;
+ mCurPixelTextureSerials[i] = 0;
+ }
+
+ mForceSetBlendState = true;
+ mForceSetRasterState = true;
+ mForceSetDepthStencilState = true;
+ mForceSetScissor = true;
+ mForceSetViewport = true;
+
+ mAppliedIBSerial = 0;
+ mAppliedStorageIBSerial = 0;
+ mAppliedIBOffset = 0;
+
+ mAppliedProgramBinarySerial = 0;
+ memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants));
+ memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants));
+
+ mInputLayoutCache.markDirty();
+
+ mCurrentVertexConstantBuffer = NULL;
+ mCurrentPixelConstantBuffer = NULL;
+ mCurrentGeometryConstantBuffer = NULL;
+
+ mCurrentPrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
+}
+
+void Renderer11::releaseDeviceResources()
+{
+ mStateCache.clear();
+ mInputLayoutCache.clear();
+
+ delete mVertexDataManager;
+ mVertexDataManager = NULL;
+
+ delete mIndexDataManager;
+ mIndexDataManager = NULL;
+
+ delete mLineLoopIB;
+ mLineLoopIB = NULL;
+
+ delete mTriangleFanIB;
+ mTriangleFanIB = NULL;
+
+ SafeRelease(mCopyVB);
+ SafeRelease(mCopySampler);
+ SafeRelease(mCopyIL);
+ SafeRelease(mCopyIL);
+ SafeRelease(mCopyVS);
+ SafeRelease(mCopyRGBAPS);
+ SafeRelease(mCopyRGBPS);
+ SafeRelease(mCopyLumPS);
+ SafeRelease(mCopyLumAlphaPS);
+
+ mCopyResourcesInitialized = false;
+
+ SafeRelease(mClearVB);
+ SafeRelease(mClearIL);
+ SafeRelease(mClearVS);
+ SafeRelease(mClearSinglePS);
+ SafeRelease(mClearMultiplePS);
+ SafeRelease(mClearScissorRS);
+ SafeRelease(mClearNoScissorRS);
+
+ mClearResourcesInitialized = false;
+
+ SafeRelease(mDriverConstantBufferVS);
+ SafeRelease(mDriverConstantBufferPS);
+ SafeRelease(mSyncQuery);
+}
+
+void Renderer11::notifyDeviceLost()
+{
+ mDeviceLost = true;
+ mDisplay->notifyDeviceLost();
+}
+
+bool Renderer11::isDeviceLost()
+{
+ return mDeviceLost;
+}
+
+// set notify to true to broadcast a message to all contexts of the device loss
+bool Renderer11::testDeviceLost(bool notify)
+{
+ bool isLost = false;
+
+ // GetRemovedReason is used to test if the device is removed
+ HRESULT result = mDevice->GetDeviceRemovedReason();
+ isLost = d3d11::isDeviceLostError(result);
+
+ if (isLost)
+ {
+ // Log error if this is a new device lost event
+ if (mDeviceLost == false)
+ {
+ ERR("The D3D11 device was removed: 0x%08X", result);
+ }
+
+ // ensure we note the device loss --
+ // we'll probably get this done again by notifyDeviceLost
+ // but best to remember it!
+ // Note that we don't want to clear the device loss status here
+ // -- this needs to be done by resetDevice
+ mDeviceLost = true;
+ if (notify)
+ {
+ notifyDeviceLost();
+ }
+ }
+
+ return isLost;
+}
+
+bool Renderer11::testDeviceResettable()
+{
+ // determine if the device is resettable by creating a dummy device
+ PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice");
+
+ if (D3D11CreateDevice == NULL)
+ {
+ return false;
+ }
+
+ D3D_FEATURE_LEVEL featureLevels[] =
+ {
+ D3D_FEATURE_LEVEL_11_0,
+ D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0,
+ };
+
+ ID3D11Device* dummyDevice;
+ D3D_FEATURE_LEVEL dummyFeatureLevel;
+ ID3D11DeviceContext* dummyContext;
+
+ HRESULT result = D3D11CreateDevice(NULL,
+ D3D_DRIVER_TYPE_HARDWARE,
+ NULL,
+ #if defined(_DEBUG)
+ D3D11_CREATE_DEVICE_DEBUG,
+ #else
+ 0,
+ #endif
+ featureLevels,
+ ArraySize(featureLevels),
+ D3D11_SDK_VERSION,
+ &dummyDevice,
+ &dummyFeatureLevel,
+ &dummyContext);
+
+ if (!mDevice || FAILED(result))
+ {
+ return false;
+ }
+
+ dummyContext->Release();
+ dummyDevice->Release();
+
+ return true;
+}
+
+void Renderer11::release()
+{
+ releaseDeviceResources();
+
+ if (mDxgiFactory)
+ {
+ mDxgiFactory->Release();
+ mDxgiFactory = NULL;
+ }
+
+ if (mDxgiAdapter)
+ {
+ mDxgiAdapter->Release();
+ mDxgiAdapter = NULL;
+ }
+
+ if (mDeviceContext)
+ {
+ mDeviceContext->ClearState();
+ mDeviceContext->Flush();
+ mDeviceContext->Release();
+ mDeviceContext = NULL;
+ }
+
+ if (mDevice)
+ {
+ mDevice->Release();
+ mDevice = NULL;
+ }
+
+ if (mD3d11Module)
+ {
+ FreeLibrary(mD3d11Module);
+ mD3d11Module = NULL;
+ }
+
+ if (mDxgiModule)
+ {
+ FreeLibrary(mDxgiModule);
+ mDxgiModule = NULL;
+ }
+}
+
+bool Renderer11::resetDevice()
+{
+ // recreate everything
+ release();
+ EGLint result = initialize();
+
+ if (result != EGL_SUCCESS)
+ {
+ ERR("Could not reinitialize D3D11 device: %08X", result);
+ return false;
+ }
+
+ mDeviceLost = false;
+
+ return true;
+}
+
+DWORD Renderer11::getAdapterVendor() const
+{
+ return mAdapterDescription.VendorId;
+}
+
+std::string Renderer11::getRendererDescription() const
+{
+ std::ostringstream rendererString;
+
+ rendererString << mDescription;
+ rendererString << " Direct3D11";
+
+ rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel();
+ rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel();
+
+ return rendererString.str();
+}
+
+GUID Renderer11::getAdapterIdentifier() const
+{
+ // Use the adapter LUID as our adapter ID
+ // This number is local to a machine is only guaranteed to be unique between restarts
+ META_ASSERT(sizeof(LUID) <= sizeof(GUID));
+ GUID adapterId = {0};
+ memcpy(&adapterId, &mAdapterDescription.AdapterLuid, sizeof(LUID));
+ return adapterId;
+}
+
+bool Renderer11::getBGRATextureSupport() const
+{
+ return mBGRATextureSupport;
+}
+
+bool Renderer11::getDXT1TextureSupport()
+{
+ return mDXT1TextureSupport;
+}
+
+bool Renderer11::getDXT3TextureSupport()
+{
+ return mDXT3TextureSupport;
+}
+
+bool Renderer11::getDXT5TextureSupport()
+{
+ return mDXT5TextureSupport;
+}
+
+bool Renderer11::getDepthTextureSupport() const
+{
+ return mDepthTextureSupport;
+}
+
+bool Renderer11::getFloat32TextureSupport(bool *filtering, bool *renderable)
+{
+ *renderable = mFloat32RenderSupport;
+ *filtering = mFloat32FilterSupport;
+ return mFloat32TextureSupport;
+}
+
+bool Renderer11::getFloat16TextureSupport(bool *filtering, bool *renderable)
+{
+ *renderable = mFloat16RenderSupport;
+ *filtering = mFloat16FilterSupport;
+ return mFloat16TextureSupport;
+}
+
+bool Renderer11::getLuminanceTextureSupport()
+{
+ return false;
+}
+
+bool Renderer11::getLuminanceAlphaTextureSupport()
+{
+ return false;
+}
+
+bool Renderer11::getTextureFilterAnisotropySupport() const
+{
+ return true;
+}
+
+float Renderer11::getTextureMaxAnisotropy() const
+{
+ switch (mFeatureLevel)
+ {
+ 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;
+ default: UNREACHABLE();
+ return 0;
+ }
+}
+
+bool Renderer11::getEventQuerySupport()
+{
+ return true;
+}
+
+Range Renderer11::getViewportBounds() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ return Range(D3D11_VIEWPORT_BOUNDS_MIN, D3D11_VIEWPORT_BOUNDS_MAX);
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return Range(D3D10_VIEWPORT_BOUNDS_MIN, D3D10_VIEWPORT_BOUNDS_MAX);
+ default: UNREACHABLE();
+ return Range(0, 0);
+ }
+}
+
+unsigned int Renderer11::getMaxVertexTextureImageUnits() const
+{
+ META_ASSERT(MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 <= gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return MAX_TEXTURE_IMAGE_UNITS_VTF_SM4;
+ default: UNREACHABLE();
+ return 0;
+ }
+}
+
+unsigned int Renderer11::getMaxCombinedTextureImageUnits() const
+{
+ return gl::MAX_TEXTURE_IMAGE_UNITS + getMaxVertexTextureImageUnits();
+}
+
+unsigned int Renderer11::getReservedVertexUniformVectors() const
+{
+ return 0; // Driver uniforms are stored in a separate constant buffer
+}
+
+unsigned int Renderer11::getReservedFragmentUniformVectors() const
+{
+ return 0; // Driver uniforms are stored in a separate constant buffer
+}
+
+unsigned int Renderer11::getMaxVertexUniformVectors() const
+{
+ META_ASSERT(MAX_VERTEX_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT);
+ ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_10_0);
+ return MAX_VERTEX_UNIFORM_VECTORS_D3D11;
+}
+
+unsigned int Renderer11::getMaxFragmentUniformVectors() const
+{
+ META_ASSERT(MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 <= D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT);
+ ASSERT(mFeatureLevel >= D3D_FEATURE_LEVEL_10_0);
+ return MAX_FRAGMENT_UNIFORM_VECTORS_D3D11;
+}
+
+unsigned int Renderer11::getMaxVaryingVectors() const
+{
+ META_ASSERT(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT);
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ return D3D11_VS_OUTPUT_REGISTER_COUNT;
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return D3D10_VS_OUTPUT_REGISTER_COUNT;
+ default: UNREACHABLE();
+ return 0;
+ }
+}
+
+bool Renderer11::getNonPower2TextureSupport() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return true;
+ default: UNREACHABLE();
+ return false;
+ }
+}
+
+bool Renderer11::getOcclusionQuerySupport() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return true;
+ default: UNREACHABLE();
+ return false;
+ }
+}
+
+bool Renderer11::getInstancingSupport() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return true;
+ default: UNREACHABLE();
+ return false;
+ }
+}
+
+bool Renderer11::getShareHandleSupport() const
+{
+ // We only currently support share handles with BGRA surfaces, because
+ // chrome needs BGRA. Once chrome fixes this, we should always support them.
+ // PIX doesn't seem to support using share handles, so disable them.
+ return getBGRATextureSupport() && !gl::perfActive();
+}
+
+bool Renderer11::getDerivativeInstructionSupport() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return true;
+ default: UNREACHABLE();
+ return false;
+ }
+}
+
+bool Renderer11::getPostSubBufferSupport() const
+{
+ // D3D11 does not support present with dirty rectangles until D3D11.1 and DXGI 1.2.
+ return false;
+}
+
+int Renderer11::getMajorShaderModel() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5
+ case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4
+ case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MAJOR_VERSION; // 4
+ default: UNREACHABLE(); return 0;
+ }
+}
+
+int Renderer11::getMinorShaderModel() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0
+ case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1
+ case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MINOR_VERSION; // 0
+ default: UNREACHABLE(); return 0;
+ }
+}
+
+float Renderer11::getMaxPointSize() const
+{
+ // choose a reasonable maximum. we enforce this in the shader.
+ // (nb: on a Radeon 2600xt, DX9 reports a 256 max point size)
+ return 1024.0f;
+}
+
+int Renderer11::getMaxViewportDimension() const
+{
+ // Maximum viewport size must be at least as large as the largest render buffer (or larger).
+ // In our case return the maximum texture size, which is the maximum render buffer size.
+ META_ASSERT(D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION * 2 - 1 <= D3D11_VIEWPORT_BOUNDS_MAX);
+ META_ASSERT(D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION * 2 - 1 <= D3D10_VIEWPORT_BOUNDS_MAX);
+
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 16384
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 8192
+ default: UNREACHABLE();
+ return 0;
+ }
+}
+
+int Renderer11::getMaxTextureWidth() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 16384
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 8192
+ default: UNREACHABLE(); return 0;
+ }
+}
+
+int Renderer11::getMaxTextureHeight() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 16384
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // 8192
+ default: UNREACHABLE(); return 0;
+ }
+}
+
+bool Renderer11::get32BitIndexSupport() const
+{
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP >= 32; // true
+ default: UNREACHABLE(); return false;
+ }
+}
+
+int Renderer11::getMinSwapInterval() const
+{
+ return 0;
+}
+
+int Renderer11::getMaxSwapInterval() const
+{
+ return 4;
+}
+
+int Renderer11::getMaxSupportedSamples() const
+{
+ return mMaxSupportedSamples;
+}
+
+int Renderer11::getNearestSupportedSamples(DXGI_FORMAT format, unsigned int requested) const
+{
+ if (requested == 0)
+ {
+ return 0;
+ }
+
+ MultisampleSupportMap::const_iterator iter = mMultisampleSupportMap.find(format);
+ if (iter != mMultisampleSupportMap.end())
+ {
+ const MultisampleSupportInfo& info = iter->second;
+ for (unsigned int i = requested - 1; i < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; i++)
+ {
+ if (info.qualityLevels[i] > 0)
+ {
+ return i + 1;
+ }
+ }
+ }
+
+ return -1;
+}
+
+unsigned int Renderer11::getMaxRenderTargets() const
+{
+ META_ASSERT(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT <= gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
+ META_ASSERT(D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT <= gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
+
+ switch (mFeatureLevel)
+ {
+ case D3D_FEATURE_LEVEL_11_0:
+ return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; // 8
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ return D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; // 8
+ default:
+ UNREACHABLE();
+ return 1;
+ }
+}
+
+bool Renderer11::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source)
+{
+ if (source && dest)
+ {
+ TextureStorage11_2D *source11 = TextureStorage11_2D::makeTextureStorage11_2D(source->getStorageInstance());
+ TextureStorage11_2D *dest11 = TextureStorage11_2D::makeTextureStorage11_2D(dest->getStorageInstance());
+
+ mDeviceContext->CopyResource(dest11->getBaseTexture(), source11->getBaseTexture());
+ return true;
+ }
+
+ return false;
+}
+
+bool Renderer11::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source)
+{
+ if (source && dest)
+ {
+ TextureStorage11_Cube *source11 = TextureStorage11_Cube::makeTextureStorage11_Cube(source->getStorageInstance());
+ TextureStorage11_Cube *dest11 = TextureStorage11_Cube::makeTextureStorage11_Cube(dest->getStorageInstance());
+
+ mDeviceContext->CopyResource(dest11->getBaseTexture(), source11->getBaseTexture());
+ return true;
+ }
+
+ return false;
+}
+
+bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level)
+{
+ gl::Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer();
+ if (!colorbuffer)
+ {
+ ERR("Failed to retrieve the color buffer from the frame buffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget());
+ if (!sourceRenderTarget)
+ {
+ ERR("Failed to retrieve the render target from the frame buffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView();
+ if (!source)
+ {
+ ERR("Failed to retrieve the render target view from the render target.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
+ if (!storage11)
+ {
+ ERR("Failed to retrieve the texture storage from the destination.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(level));
+ if (!destRenderTarget)
+ {
+ ERR("Failed to retrieve the render target from the destination storage.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView();
+ if (!dest)
+ {
+ ERR("Failed to retrieve the render target view from the destination render target.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ gl::Rectangle destRect;
+ destRect.x = xoffset;
+ destRect.y = yoffset;
+ destRect.width = sourceRect.width;
+ destRect.height = sourceRect.height;
+
+ bool ret = copyTexture(source, sourceRect, sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(),
+ dest, destRect, destRenderTarget->getWidth(), destRenderTarget->getHeight(), destFormat);
+
+ return ret;
+}
+
+bool Renderer11::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level)
+{
+ gl::Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer();
+ if (!colorbuffer)
+ {
+ ERR("Failed to retrieve the color buffer from the frame buffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget());
+ if (!sourceRenderTarget)
+ {
+ ERR("Failed to retrieve the render target from the frame buffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView();
+ if (!source)
+ {
+ ERR("Failed to retrieve the render target view from the render target.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
+ if (!storage11)
+ {
+ ERR("Failed to retrieve the texture storage from the destination.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(target, level));
+ if (!destRenderTarget)
+ {
+ ERR("Failed to retrieve the render target from the destination storage.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView();
+ if (!dest)
+ {
+ ERR("Failed to retrieve the render target view from the destination render target.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ gl::Rectangle destRect;
+ destRect.x = xoffset;
+ destRect.y = yoffset;
+ destRect.width = sourceRect.width;
+ destRect.height = sourceRect.height;
+
+ bool ret = copyTexture(source, sourceRect, sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(),
+ dest, destRect, destRenderTarget->getWidth(), destRenderTarget->getHeight(), destFormat);
+
+ return ret;
+}
+
+bool Renderer11::copyTexture(ID3D11ShaderResourceView *source, const gl::Rectangle &sourceArea, unsigned int sourceWidth, unsigned int sourceHeight,
+ ID3D11RenderTargetView *dest, const gl::Rectangle &destArea, unsigned int destWidth, unsigned int destHeight, GLenum destFormat)
+{
+ HRESULT result;
+
+ if (!mCopyResourcesInitialized)
+ {
+ ASSERT(!mCopyVB && !mCopySampler && !mCopyIL && !mCopyVS && !mCopyRGBAPS && !mCopyRGBPS && !mCopyLumPS && !mCopyLumAlphaPS);
+
+ D3D11_BUFFER_DESC vbDesc;
+ vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4;
+ vbDesc.Usage = D3D11_USAGE_DYNAMIC;
+ vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ vbDesc.MiscFlags = 0;
+ vbDesc.StructureByteStride = 0;
+
+ result = mDevice->CreateBuffer(&vbDesc, NULL, &mCopyVB);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mCopyVB, "Renderer11 copy texture vertex buffer");
+
+ D3D11_SAMPLER_DESC samplerDesc;
+ samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.MipLODBias = 0.0f;
+ samplerDesc.MaxAnisotropy = 0;
+ samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+ samplerDesc.BorderColor[0] = 0.0f;
+ samplerDesc.BorderColor[1] = 0.0f;
+ samplerDesc.BorderColor[2] = 0.0f;
+ samplerDesc.BorderColor[3] = 0.0f;
+ samplerDesc.MinLOD = 0.0f;
+ samplerDesc.MaxLOD = 0.0f;
+
+ result = mDevice->CreateSamplerState(&samplerDesc, &mCopySampler);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mCopySampler, "Renderer11 copy sampler");
+
+ D3D11_INPUT_ELEMENT_DESC quadLayout[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+
+ result = mDevice->CreateInputLayout(quadLayout, 2, g_VS_Passthrough, sizeof(g_VS_Passthrough), &mCopyIL);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mCopyIL, "Renderer11 copy texture input layout");
+
+ result = mDevice->CreateVertexShader(g_VS_Passthrough, sizeof(g_VS_Passthrough), NULL, &mCopyVS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mCopyVS, "Renderer11 copy texture vertex shader");
+
+ result = mDevice->CreatePixelShader(g_PS_PassthroughRGBA, sizeof(g_PS_PassthroughRGBA), NULL, &mCopyRGBAPS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mCopyRGBAPS, "Renderer11 copy texture RGBA pixel shader");
+
+ result = mDevice->CreatePixelShader(g_PS_PassthroughRGB, sizeof(g_PS_PassthroughRGB), NULL, &mCopyRGBPS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mCopyRGBPS, "Renderer11 copy texture RGB pixel shader");
+
+ result = mDevice->CreatePixelShader(g_PS_PassthroughLum, sizeof(g_PS_PassthroughLum), NULL, &mCopyLumPS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mCopyLumPS, "Renderer11 copy texture luminance pixel shader");
+
+ result = mDevice->CreatePixelShader(g_PS_PassthroughLumAlpha, sizeof(g_PS_PassthroughLumAlpha), NULL, &mCopyLumAlphaPS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mCopyLumAlphaPS, "Renderer11 copy texture luminance alpha pixel shader");
+
+ mCopyResourcesInitialized = true;
+ }
+
+ // Verify the source and destination area sizes
+ if (sourceArea.x < 0 || sourceArea.x + sourceArea.width > static_cast<int>(sourceWidth) ||
+ sourceArea.y < 0 || sourceArea.y + sourceArea.height > static_cast<int>(sourceHeight) ||
+ destArea.x < 0 || destArea.x + destArea.width > static_cast<int>(destWidth) ||
+ destArea.y < 0 || destArea.y + destArea.height > static_cast<int>(destHeight))
+ {
+ return gl::error(GL_INVALID_VALUE, false);
+ }
+
+ // Set vertices
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ result = mDeviceContext->Map(mCopyVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ ERR("Failed to map vertex buffer for texture copy, HRESULT: 0x%X.", result);
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ d3d11::PositionTexCoordVertex *vertices = static_cast<d3d11::PositionTexCoordVertex*>(mappedResource.pData);
+
+ // Create a quad in homogeneous coordinates
+ float x1 = (destArea.x / float(destWidth)) * 2.0f - 1.0f;
+ float y1 = ((destHeight - destArea.y - destArea.height) / float(destHeight)) * 2.0f - 1.0f;
+ float x2 = ((destArea.x + destArea.width) / float(destWidth)) * 2.0f - 1.0f;
+ float y2 = ((destHeight - destArea.y) / float(destHeight)) * 2.0f - 1.0f;
+
+ float u1 = sourceArea.x / float(sourceWidth);
+ float v1 = sourceArea.y / float(sourceHeight);
+ float u2 = (sourceArea.x + sourceArea.width) / float(sourceWidth);
+ float v2 = (sourceArea.y + sourceArea.height) / float(sourceHeight);
+
+ 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);
+
+ mDeviceContext->Unmap(mCopyVB, 0);
+
+ static UINT stride = sizeof(d3d11::PositionTexCoordVertex);
+ static UINT startIdx = 0;
+ mDeviceContext->IASetVertexBuffers(0, 1, &mCopyVB, &stride, &startIdx);
+
+ // Apply state
+ mDeviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF);
+ mDeviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF);
+ mDeviceContext->RSSetState(NULL);
+
+ // Apply shaders
+ mDeviceContext->IASetInputLayout(mCopyIL);
+ mDeviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ mDeviceContext->VSSetShader(mCopyVS, NULL, 0);
+
+ ID3D11PixelShader *ps = NULL;
+ switch(destFormat)
+ {
+ case GL_RGBA: ps = mCopyRGBAPS; break;
+ case GL_RGB: ps = mCopyRGBPS; break;
+ case GL_ALPHA: ps = mCopyRGBAPS; break;
+ case GL_BGRA_EXT: ps = mCopyRGBAPS; break;
+ case GL_LUMINANCE: ps = mCopyLumPS; break;
+ case GL_LUMINANCE_ALPHA: ps = mCopyLumAlphaPS; break;
+ default: UNREACHABLE(); ps = NULL; break;
+ }
+
+ mDeviceContext->PSSetShader(ps, NULL, 0);
+ mDeviceContext->GSSetShader(NULL, NULL, 0);
+
+ // Unset the currently bound shader resource to avoid conflicts
+ static ID3D11ShaderResourceView *const nullSRV = NULL;
+ mDeviceContext->PSSetShaderResources(0, 1, &nullSRV);
+
+ // Apply render target
+ setOneTimeRenderTarget(dest);
+
+ // Set the viewport
+ D3D11_VIEWPORT viewport;
+ viewport.TopLeftX = 0;
+ viewport.TopLeftY = 0;
+ viewport.Width = destWidth;
+ viewport.Height = destHeight;
+ viewport.MinDepth = 0.0f;
+ viewport.MaxDepth = 1.0f;
+ mDeviceContext->RSSetViewports(1, &viewport);
+
+ // Apply textures
+ mDeviceContext->PSSetShaderResources(0, 1, &source);
+ mDeviceContext->PSSetSamplers(0, 1, &mCopySampler);
+
+ // Draw the quad
+ mDeviceContext->Draw(4, 0);
+
+ // Unbind textures and render targets and vertex buffer
+ mDeviceContext->PSSetShaderResources(0, 1, &nullSRV);
+
+ unapplyRenderTargets();
+
+ UINT zero = 0;
+ ID3D11Buffer *const nullBuffer = NULL;
+ mDeviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero);
+
+ markAllStateDirty();
+
+ return true;
+}
+
+void Renderer11::unapplyRenderTargets()
+{
+ setOneTimeRenderTarget(NULL);
+}
+
+void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView)
+{
+ ID3D11RenderTargetView *rtvArray[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL};
+
+ rtvArray[0] = renderTargetView;
+
+ mDeviceContext->OMSetRenderTargets(getMaxRenderTargets(), rtvArray, NULL);
+
+ // Do not preserve the serial for this one-time-use render target
+ for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++)
+ {
+ mAppliedRenderTargetSerials[rtIndex] = 0;
+ }
+}
+
+RenderTarget *Renderer11::createRenderTarget(SwapChain *swapChain, bool depth)
+{
+ SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain);
+ RenderTarget11 *renderTarget = NULL;
+
+ if (depth)
+ {
+ // Note: depth stencil may be NULL for 0 sized surfaces
+ renderTarget = new RenderTarget11(this, swapChain11->getDepthStencil(),
+ swapChain11->getDepthStencilTexture(), NULL,
+ swapChain11->getWidth(), swapChain11->getHeight());
+ }
+ else
+ {
+ // Note: render target may be NULL for 0 sized surfaces
+ renderTarget = new RenderTarget11(this, swapChain11->getRenderTarget(),
+ swapChain11->getOffscreenTexture(),
+ swapChain11->getRenderTargetShaderResource(),
+ swapChain11->getWidth(), swapChain11->getHeight());
+ }
+ return renderTarget;
+}
+
+RenderTarget *Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth)
+{
+ RenderTarget11 *renderTarget = new RenderTarget11(this, width, height, format, samples, depth);
+ return renderTarget;
+}
+
+ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type)
+{
+ ShaderExecutable11 *executable = NULL;
+
+ switch (type)
+ {
+ case rx::SHADER_VERTEX:
+ {
+ ID3D11VertexShader *vshader = NULL;
+ HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vshader);
+ ASSERT(SUCCEEDED(result));
+
+ if (vshader)
+ {
+ executable = new ShaderExecutable11(function, length, vshader);
+ }
+ }
+ break;
+ case rx::SHADER_PIXEL:
+ {
+ ID3D11PixelShader *pshader = NULL;
+ HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pshader);
+ ASSERT(SUCCEEDED(result));
+
+ if (pshader)
+ {
+ executable = new ShaderExecutable11(function, length, pshader);
+ }
+ }
+ break;
+ case rx::SHADER_GEOMETRY:
+ {
+ ID3D11GeometryShader *gshader = NULL;
+ HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &gshader);
+ ASSERT(SUCCEEDED(result));
+
+ if (gshader)
+ {
+ executable = new ShaderExecutable11(function, length, gshader);
+ }
+ }
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ return executable;
+}
+
+ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type)
+{
+ const char *profile = NULL;
+
+ switch (type)
+ {
+ case rx::SHADER_VERTEX:
+ profile = "vs_4_0";
+ break;
+ case rx::SHADER_PIXEL:
+ profile = "ps_4_0";
+ break;
+ case rx::SHADER_GEOMETRY:
+ profile = "gs_4_0";
+ break;
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+
+ ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, D3DCOMPILE_OPTIMIZATION_LEVEL0, false);
+ if (!binary)
+ return NULL;
+
+ ShaderExecutable *executable = loadExecutable((DWORD *)binary->GetBufferPointer(), binary->GetBufferSize(), type);
+ binary->Release();
+
+ return executable;
+}
+
+VertexBuffer *Renderer11::createVertexBuffer()
+{
+ return new VertexBuffer11(this);
+}
+
+IndexBuffer *Renderer11::createIndexBuffer()
+{
+ return new IndexBuffer11(this);
+}
+
+BufferStorage *Renderer11::createBufferStorage()
+{
+ return new BufferStorage11(this);
+}
+
+QueryImpl *Renderer11::createQuery(GLenum type)
+{
+ return new Query11(this, type);
+}
+
+FenceImpl *Renderer11::createFence()
+{
+ return new Fence11(this);
+}
+
+bool Renderer11::getRenderTargetResource(gl::Renderbuffer *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource)
+{
+ ASSERT(colorbuffer != NULL);
+
+ RenderTarget11 *renderTarget = RenderTarget11::makeRenderTarget11(colorbuffer->getRenderTarget());
+ if (renderTarget)
+ {
+ *subresourceIndex = renderTarget->getSubresourceIndex();
+
+ ID3D11RenderTargetView *colorBufferRTV = renderTarget->getRenderTargetView();
+ if (colorBufferRTV)
+ {
+ ID3D11Resource *textureResource = NULL;
+ colorBufferRTV->GetResource(&textureResource);
+
+ if (textureResource)
+ {
+ HRESULT result = textureResource->QueryInterface(IID_ID3D11Texture2D, (void**)resource);
+ textureResource->Release();
+
+ if (SUCCEEDED(result))
+ {
+ return true;
+ }
+ else
+ {
+ ERR("Failed to extract the ID3D11Texture2D from the render target resource, "
+ "HRESULT: 0x%X.", result);
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect,
+ bool blitRenderTarget, bool blitDepthStencil)
+{
+ if (blitRenderTarget)
+ {
+ gl::Renderbuffer *readBuffer = readTarget->getReadColorbuffer();
+
+ if (!readBuffer)
+ {
+ ERR("Failed to retrieve the read buffer from the read framebuffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ RenderTarget *readRenderTarget = readBuffer->getRenderTarget();
+
+ for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
+ {
+ if (drawTarget->isEnabledColorAttachment(colorAttachment))
+ {
+ gl::Renderbuffer *drawBuffer = drawTarget->getColorbuffer(colorAttachment);
+
+ if (!drawBuffer)
+ {
+ ERR("Failed to retrieve the draw buffer from the draw framebuffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ RenderTarget *drawRenderTarget = drawBuffer->getRenderTarget();
+
+ if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, false))
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ if (blitDepthStencil)
+ {
+ gl::Renderbuffer *readBuffer = readTarget->getDepthOrStencilbuffer();
+ gl::Renderbuffer *drawBuffer = drawTarget->getDepthOrStencilbuffer();
+
+ if (!readBuffer)
+ {
+ ERR("Failed to retrieve the read depth-stencil buffer from the read framebuffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ if (!drawBuffer)
+ {
+ ERR("Failed to retrieve the draw depth-stencil buffer from the draw framebuffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ RenderTarget *readRenderTarget = readBuffer->getDepthStencil();
+ RenderTarget *drawRenderTarget = drawBuffer->getDepthStencil();
+
+ if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, true))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void Renderer11::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels)
+{
+ ID3D11Texture2D *colorBufferTexture = NULL;
+ unsigned int subresourceIndex = 0;
+
+ gl::Renderbuffer *colorbuffer = framebuffer->getReadColorbuffer();
+
+ if (colorbuffer && getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
+ {
+ gl::Rectangle area;
+ area.x = x;
+ area.y = y;
+ area.width = width;
+ area.height = height;
+
+ readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch,
+ packReverseRowOrder, packAlignment, pixels);
+
+ colorBufferTexture->Release();
+ colorBufferTexture = NULL;
+ }
+}
+
+Image *Renderer11::createImage()
+{
+ return new Image11();
+}
+
+void Renderer11::generateMipmap(Image *dest, Image *src)
+{
+ Image11 *dest11 = Image11::makeImage11(dest);
+ Image11 *src11 = Image11::makeImage11(src);
+ Image11::generateMipmap(dest11, src11);
+}
+
+TextureStorage *Renderer11::createTextureStorage2D(SwapChain *swapChain)
+{
+ SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain);
+ return new TextureStorage11_2D(this, swapChain11);
+}
+
+TextureStorage *Renderer11::createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
+{
+ return new TextureStorage11_2D(this, levels, internalformat, usage, forceRenderable, width, height);
+}
+
+TextureStorage *Renderer11::createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
+{
+ return new TextureStorage11_Cube(this, levels, internalformat, usage, forceRenderable, size);
+}
+
+static inline unsigned int getFastPixelCopySize(DXGI_FORMAT sourceFormat, GLenum destFormat, GLenum destType)
+{
+ if (sourceFormat == DXGI_FORMAT_A8_UNORM &&
+ destFormat == GL_ALPHA &&
+ destType == GL_UNSIGNED_BYTE)
+ {
+ return 1;
+ }
+ else if (sourceFormat == DXGI_FORMAT_R8G8B8A8_UNORM &&
+ destFormat == GL_RGBA &&
+ destType == GL_UNSIGNED_BYTE)
+ {
+ return 4;
+ }
+ else if (sourceFormat == DXGI_FORMAT_B8G8R8A8_UNORM &&
+ destFormat == GL_BGRA_EXT &&
+ destType == GL_UNSIGNED_BYTE)
+ {
+ return 4;
+ }
+ else if (sourceFormat == DXGI_FORMAT_R16G16B16A16_FLOAT &&
+ destFormat == GL_RGBA &&
+ destType == GL_HALF_FLOAT_OES)
+ {
+ return 8;
+ }
+ else if (sourceFormat == DXGI_FORMAT_R32G32B32_FLOAT &&
+ destFormat == GL_RGB &&
+ destType == GL_FLOAT)
+ {
+ return 12;
+ }
+ else if (sourceFormat == DXGI_FORMAT_R32G32B32A32_FLOAT &&
+ destFormat == GL_RGBA &&
+ destType == GL_FLOAT)
+ {
+ return 16;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static inline void readPixelColor(const unsigned char *data, DXGI_FORMAT format, unsigned int x,
+ unsigned int y, int inputPitch, gl::Color *outColor)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ {
+ unsigned int rgba = *reinterpret_cast<const unsigned int*>(data + 4 * x + y * inputPitch);
+ outColor->red = (rgba & 0x000000FF) * (1.0f / 0x000000FF);
+ outColor->green = (rgba & 0x0000FF00) * (1.0f / 0x0000FF00);
+ outColor->blue = (rgba & 0x00FF0000) * (1.0f / 0x00FF0000);
+ outColor->alpha = (rgba & 0xFF000000) * (1.0f / 0xFF000000);
+ }
+ break;
+
+ case DXGI_FORMAT_A8_UNORM:
+ {
+ outColor->red = 0.0f;
+ outColor->green = 0.0f;
+ outColor->blue = 0.0f;
+ outColor->alpha = *(data + x + y * inputPitch) / 255.0f;
+ }
+ break;
+
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ {
+ outColor->red = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 0);
+ outColor->green = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 1);
+ outColor->blue = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 2);
+ outColor->alpha = *(reinterpret_cast<const float*>(data + 16 * x + y * inputPitch) + 3);
+ }
+ break;
+
+ case DXGI_FORMAT_R32G32B32_FLOAT:
+ {
+ outColor->red = *(reinterpret_cast<const float*>(data + 12 * x + y * inputPitch) + 0);
+ outColor->green = *(reinterpret_cast<const float*>(data + 12 * x + y * inputPitch) + 1);
+ outColor->blue = *(reinterpret_cast<const float*>(data + 12 * x + y * inputPitch) + 2);
+ outColor->alpha = 1.0f;
+ }
+ break;
+
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ {
+ outColor->red = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 0));
+ outColor->green = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 1));
+ outColor->blue = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 2));
+ outColor->alpha = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 8 * x + y * inputPitch) + 3));
+ }
+ break;
+
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ {
+ unsigned int bgra = *reinterpret_cast<const unsigned int*>(data + 4 * x + y * inputPitch);
+ outColor->red = (bgra & 0x00FF0000) * (1.0f / 0x00FF0000);
+ outColor->blue = (bgra & 0x000000FF) * (1.0f / 0x000000FF);
+ outColor->green = (bgra & 0x0000FF00) * (1.0f / 0x0000FF00);
+ outColor->alpha = (bgra & 0xFF000000) * (1.0f / 0xFF000000);
+ }
+ break;
+
+ case DXGI_FORMAT_R8_UNORM:
+ {
+ outColor->red = *(data + x + y * inputPitch) / 255.0f;
+ outColor->green = 0.0f;
+ outColor->blue = 0.0f;
+ outColor->alpha = 1.0f;
+ }
+ break;
+
+ case DXGI_FORMAT_R8G8_UNORM:
+ {
+ unsigned short rg = *reinterpret_cast<const unsigned short*>(data + 2 * x + y * inputPitch);
+
+ outColor->red = (rg & 0xFF00) * (1.0f / 0xFF00);
+ outColor->green = (rg & 0x00FF) * (1.0f / 0x00FF);
+ outColor->blue = 0.0f;
+ outColor->alpha = 1.0f;
+ }
+ break;
+
+ case DXGI_FORMAT_R16_FLOAT:
+ {
+ outColor->red = gl::float16ToFloat32(*reinterpret_cast<const unsigned short*>(data + 2 * x + y * inputPitch));
+ outColor->green = 0.0f;
+ outColor->blue = 0.0f;
+ outColor->alpha = 1.0f;
+ }
+ break;
+
+ case DXGI_FORMAT_R16G16_FLOAT:
+ {
+ outColor->red = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 4 * x + y * inputPitch) + 0));
+ outColor->green = gl::float16ToFloat32(*(reinterpret_cast<const unsigned short*>(data + 4 * x + y * inputPitch) + 1));
+ outColor->blue = 0.0f;
+ outColor->alpha = 1.0f;
+ }
+ break;
+
+ default:
+ ERR("ReadPixelColor not implemented for DXGI format %u.", format);
+ UNIMPLEMENTED();
+ break;
+ }
+}
+
+static inline void writePixelColor(const gl::Color &color, GLenum format, GLenum type, unsigned int x,
+ unsigned int y, int outputPitch, void *outData)
+{
+ unsigned char* byteData = reinterpret_cast<unsigned char*>(outData);
+ unsigned short* shortData = reinterpret_cast<unsigned short*>(outData);
+
+ switch (format)
+ {
+ case GL_RGBA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ byteData[4 * x + y * outputPitch + 0] = static_cast<unsigned char>(255 * color.red + 0.5f);
+ byteData[4 * x + y * outputPitch + 1] = static_cast<unsigned char>(255 * color.green + 0.5f);
+ byteData[4 * x + y * outputPitch + 2] = static_cast<unsigned char>(255 * color.blue + 0.5f);
+ byteData[4 * x + y * outputPitch + 3] = static_cast<unsigned char>(255 * color.alpha + 0.5f);
+ break;
+
+ default:
+ ERR("WritePixelColor not implemented for format GL_RGBA and type 0x%X.", type);
+ UNIMPLEMENTED();
+ break;
+ }
+ break;
+
+ case GL_BGRA_EXT:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ byteData[4 * x + y * outputPitch + 0] = static_cast<unsigned char>(255 * color.blue + 0.5f);
+ byteData[4 * x + y * outputPitch + 1] = static_cast<unsigned char>(255 * color.green + 0.5f);
+ byteData[4 * x + y * outputPitch + 2] = static_cast<unsigned char>(255 * color.red + 0.5f);
+ byteData[4 * x + y * outputPitch + 3] = static_cast<unsigned char>(255 * color.alpha + 0.5f);
+ break;
+
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
+ // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
+ // this type is packed as follows:
+ // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ // --------------------------------------------------------------------------------
+ // | 4th | 3rd | 2nd | 1st component |
+ // --------------------------------------------------------------------------------
+ // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
+ shortData[x + y * outputPitch / sizeof(unsigned short)] =
+ (static_cast<unsigned short>(15 * color.alpha + 0.5f) << 12) |
+ (static_cast<unsigned short>(15 * color.red + 0.5f) << 8) |
+ (static_cast<unsigned short>(15 * color.green + 0.5f) << 4) |
+ (static_cast<unsigned short>(15 * color.blue + 0.5f) << 0);
+ break;
+
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
+ // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
+ // this type is packed as follows:
+ // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ // --------------------------------------------------------------------------------
+ // | 4th | 3rd | 2nd | 1st component |
+ // --------------------------------------------------------------------------------
+ // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
+ shortData[x + y * outputPitch / sizeof(unsigned short)] =
+ (static_cast<unsigned short>( color.alpha + 0.5f) << 15) |
+ (static_cast<unsigned short>(31 * color.red + 0.5f) << 10) |
+ (static_cast<unsigned short>(31 * color.green + 0.5f) << 5) |
+ (static_cast<unsigned short>(31 * color.blue + 0.5f) << 0);
+ break;
+
+ default:
+ ERR("WritePixelColor not implemented for format GL_BGRA_EXT and type 0x%X.", type);
+ UNIMPLEMENTED();
+ break;
+ }
+ break;
+
+ case GL_RGB:
+ switch (type)
+ {
+ case GL_UNSIGNED_SHORT_5_6_5:
+ shortData[x + y * outputPitch / sizeof(unsigned short)] =
+ (static_cast<unsigned short>(31 * color.blue + 0.5f) << 0) |
+ (static_cast<unsigned short>(63 * color.green + 0.5f) << 5) |
+ (static_cast<unsigned short>(31 * color.red + 0.5f) << 11);
+ break;
+
+ case GL_UNSIGNED_BYTE:
+ byteData[3 * x + y * outputPitch + 0] = static_cast<unsigned char>(255 * color.red + 0.5f);
+ byteData[3 * x + y * outputPitch + 1] = static_cast<unsigned char>(255 * color.green + 0.5f);
+ byteData[3 * x + y * outputPitch + 2] = static_cast<unsigned char>(255 * color.blue + 0.5f);
+ break;
+
+ default:
+ ERR("WritePixelColor not implemented for format GL_RGB and type 0x%X.", type);
+ UNIMPLEMENTED();
+ break;
+ }
+ break;
+
+ default:
+ ERR("WritePixelColor not implemented for format 0x%X.", format);
+ UNIMPLEMENTED();
+ break;
+ }
+}
+
+void Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area,
+ GLenum format, GLenum type, GLsizei outputPitch, bool packReverseRowOrder,
+ GLint packAlignment, void *pixels)
+{
+ D3D11_TEXTURE2D_DESC textureDesc;
+ texture->GetDesc(&textureDesc);
+
+ D3D11_TEXTURE2D_DESC stagingDesc;
+ stagingDesc.Width = area.width;
+ stagingDesc.Height = area.height;
+ stagingDesc.MipLevels = 1;
+ stagingDesc.ArraySize = 1;
+ stagingDesc.Format = textureDesc.Format;
+ stagingDesc.SampleDesc.Count = 1;
+ stagingDesc.SampleDesc.Quality = 0;
+ stagingDesc.Usage = D3D11_USAGE_STAGING;
+ stagingDesc.BindFlags = 0;
+ stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ stagingDesc.MiscFlags = 0;
+
+ ID3D11Texture2D* stagingTex = NULL;
+ HRESULT result = mDevice->CreateTexture2D(&stagingDesc, NULL, &stagingTex);
+ if (FAILED(result))
+ {
+ ERR("Failed to create staging texture for readPixels, HRESULT: 0x%X.", result);
+ return;
+ }
+
+ ID3D11Texture2D* srcTex = NULL;
+ if (textureDesc.SampleDesc.Count > 1)
+ {
+ D3D11_TEXTURE2D_DESC resolveDesc;
+ resolveDesc.Width = textureDesc.Width;
+ resolveDesc.Height = textureDesc.Height;
+ resolveDesc.MipLevels = 1;
+ resolveDesc.ArraySize = 1;
+ resolveDesc.Format = textureDesc.Format;
+ resolveDesc.SampleDesc.Count = 1;
+ resolveDesc.SampleDesc.Quality = 0;
+ resolveDesc.Usage = D3D11_USAGE_DEFAULT;
+ resolveDesc.BindFlags = 0;
+ resolveDesc.CPUAccessFlags = 0;
+ resolveDesc.MiscFlags = 0;
+
+ result = mDevice->CreateTexture2D(&resolveDesc, NULL, &srcTex);
+ if (FAILED(result))
+ {
+ ERR("Failed to create resolve texture for readPixels, HRESULT: 0x%X.", result);
+ stagingTex->Release();
+ return;
+ }
+
+ mDeviceContext->ResolveSubresource(srcTex, 0, texture, subResource, textureDesc.Format);
+ subResource = 0;
+ }
+ else
+ {
+ srcTex = texture;
+ srcTex->AddRef();
+ }
+
+ D3D11_BOX srcBox;
+ srcBox.left = area.x;
+ srcBox.right = area.x + area.width;
+ srcBox.top = area.y;
+ srcBox.bottom = area.y + area.height;
+ srcBox.front = 0;
+ srcBox.back = 1;
+
+ mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox);
+
+ srcTex->Release();
+ srcTex = NULL;
+
+ D3D11_MAPPED_SUBRESOURCE mapping;
+ mDeviceContext->Map(stagingTex, 0, D3D11_MAP_READ, 0, &mapping);
+
+ unsigned char *source;
+ int inputPitch;
+ if (packReverseRowOrder)
+ {
+ source = static_cast<unsigned char*>(mapping.pData) + mapping.RowPitch * (area.height - 1);
+ inputPitch = -static_cast<int>(mapping.RowPitch);
+ }
+ else
+ {
+ source = static_cast<unsigned char*>(mapping.pData);
+ inputPitch = static_cast<int>(mapping.RowPitch);
+ }
+
+ unsigned int fastPixelSize = getFastPixelCopySize(textureDesc.Format, format, type);
+ if (fastPixelSize != 0)
+ {
+ unsigned char *dest = static_cast<unsigned char*>(pixels);
+ for (int j = 0; j < area.height; j++)
+ {
+ memcpy(dest + j * outputPitch, source + j * inputPitch, area.width * fastPixelSize);
+ }
+ }
+ else if (textureDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM &&
+ format == GL_RGBA &&
+ type == GL_UNSIGNED_BYTE)
+ {
+ // Fast path for swapping red with blue
+ unsigned char *dest = static_cast<unsigned char*>(pixels);
+
+ for (int j = 0; j < area.height; j++)
+ {
+ for (int i = 0; i < area.width; i++)
+ {
+ unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
+ *(unsigned int*)(dest + 4 * i + j * outputPitch) =
+ (argb & 0xFF00FF00) | // Keep alpha and green
+ (argb & 0x00FF0000) >> 16 | // Move red to blue
+ (argb & 0x000000FF) << 16; // Move blue to red
+ }
+ }
+ }
+ else
+ {
+ gl::Color pixelColor;
+ for (int j = 0; j < area.height; j++)
+ {
+ for (int i = 0; i < area.width; i++)
+ {
+ readPixelColor(source, textureDesc.Format, i, j, inputPitch, &pixelColor);
+ writePixelColor(pixelColor, format, type, i, j, outputPitch, pixels);
+ }
+ }
+ }
+
+ mDeviceContext->Unmap(stagingTex, 0);
+
+ stagingTex->Release();
+ stagingTex = NULL;
+}
+
+bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget,
+ RenderTarget *drawRenderTarget, bool wholeBufferCopy)
+{
+ ASSERT(readRect.width == drawRect.width && readRect.height == drawRect.height);
+
+ RenderTarget11 *drawRenderTarget11 = RenderTarget11::makeRenderTarget11(drawRenderTarget);
+ if (!drawRenderTarget)
+ {
+ ERR("Failed to retrieve the draw render target from the draw framebuffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ ID3D11Texture2D *drawTexture = drawRenderTarget11->getTexture();
+ unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex();
+
+ RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget);
+ if (!readRenderTarget)
+ {
+ ERR("Failed to retrieve the read render target from the read framebuffer.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ ID3D11Texture2D *readTexture = NULL;
+ unsigned int readSubresource = 0;
+ if (readRenderTarget->getSamples() > 0)
+ {
+ readTexture = resolveMultisampledTexture(readRenderTarget11->getTexture(), readRenderTarget11->getSubresourceIndex());
+ readSubresource = 0;
+ }
+ else
+ {
+ readTexture = readRenderTarget11->getTexture();
+ readTexture->AddRef();
+ readSubresource = readRenderTarget11->getSubresourceIndex();
+ }
+
+ if (!readTexture)
+ {
+ ERR("Failed to retrieve the read render target view from the read render target.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ D3D11_BOX readBox;
+ readBox.left = readRect.x;
+ readBox.right = readRect.x + readRect.width;
+ readBox.top = readRect.y;
+ readBox.bottom = readRect.y + readRect.height;
+ readBox.front = 0;
+ readBox.back = 1;
+
+ // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox
+ // We also require complete framebuffer copies for depth-stencil blit.
+ D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox;
+
+ mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, drawRect.x, drawRect.y, 0,
+ readTexture, readSubresource, pSrcBox);
+
+ SafeRelease(readTexture);
+
+ return true;
+}
+
+ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource)
+{
+ D3D11_TEXTURE2D_DESC textureDesc;
+ source->GetDesc(&textureDesc);
+
+ if (textureDesc.SampleDesc.Count > 1)
+ {
+ D3D11_TEXTURE2D_DESC resolveDesc;
+ resolveDesc.Width = textureDesc.Width;
+ resolveDesc.Height = textureDesc.Height;
+ resolveDesc.MipLevels = 1;
+ resolveDesc.ArraySize = 1;
+ resolveDesc.Format = textureDesc.Format;
+ resolveDesc.SampleDesc.Count = 1;
+ resolveDesc.SampleDesc.Quality = 0;
+ resolveDesc.Usage = textureDesc.Usage;
+ resolveDesc.BindFlags = textureDesc.BindFlags;
+ resolveDesc.CPUAccessFlags = 0;
+ resolveDesc.MiscFlags = 0;
+
+ ID3D11Texture2D *resolveTexture = NULL;
+ HRESULT result = mDevice->CreateTexture2D(&resolveDesc, NULL, &resolveTexture);
+ if (FAILED(result))
+ {
+ ERR("Failed to create a multisample resolve texture, HRESULT: 0x%X.", result);
+ return NULL;
+ }
+
+ mDeviceContext->ResolveSubresource(resolveTexture, 0, source, subresource, textureDesc.Format);
+ return resolveTexture;
+ }
+ else
+ {
+ source->AddRef();
+ return source;
+ }
+}
+
+bool Renderer11::getLUID(LUID *adapterLuid) const
+{
+ adapterLuid->HighPart = 0;
+ adapterLuid->LowPart = 0;
+
+ if (!mDxgiAdapter)
+ {
+ return false;
+ }
+
+ DXGI_ADAPTER_DESC adapterDesc;
+ if (FAILED(mDxgiAdapter->GetDesc(&adapterDesc)))
+ {
+ return false;
+ }
+
+ *adapterLuid = adapterDesc.AdapterLuid;
+ return true;
+}
+
+}
diff --git a/src/libGLESv2/renderer/Renderer11.h b/src/libGLESv2/renderer/Renderer11.h
new file mode 100644
index 00000000..f024855f
--- /dev/null
+++ b/src/libGLESv2/renderer/Renderer11.h
@@ -0,0 +1,358 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderer11.h: Defines a back-end specific class for the D3D11 renderer.
+
+#ifndef LIBGLESV2_RENDERER_RENDERER11_H_
+#define LIBGLESV2_RENDERER_RENDERER11_H_
+
+#include "common/angleutils.h"
+#include "libGLESv2/angletypes.h"
+#include "libGLESv2/mathutil.h"
+
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/renderer/RenderStateCache.h"
+#include "libGLESv2/renderer/InputLayoutCache.h"
+#include "libGLESv2/renderer/RenderTarget.h"
+
+namespace gl
+{
+class Renderbuffer;
+}
+
+namespace rx
+{
+
+class VertexDataManager;
+class IndexDataManager;
+class StreamingIndexBufferInterface;
+
+enum
+{
+ MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024,
+ MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024
+};
+
+class Renderer11 : public Renderer
+{
+ public:
+ Renderer11(egl::Display *display, HDC hDc);
+ virtual ~Renderer11();
+
+ static Renderer11 *makeRenderer11(Renderer *renderer);
+
+ virtual EGLint initialize();
+ virtual bool resetDevice();
+
+ virtual int generateConfigs(ConfigDesc **configDescList);
+ virtual void deleteConfigs(ConfigDesc *configDescList);
+
+ virtual void sync(bool block);
+
+ virtual SwapChain *createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat);
+
+ virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler);
+ virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture);
+
+ virtual void setRasterizerState(const gl::RasterizerState &rasterState);
+ virtual void setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor,
+ unsigned int sampleMask);
+ virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
+ int stencilBackRef, bool frontFaceCCW);
+
+ virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled);
+ virtual bool setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
+ bool ignoreViewport);
+
+ virtual bool applyPrimitiveType(GLenum mode, GLsizei count);
+ virtual bool applyRenderTarget(gl::Framebuffer *frameBuffer);
+ virtual void applyShaders(gl::ProgramBinary *programBinary);
+ virtual void applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray);
+ virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances);
+ virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
+
+ virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances);
+ virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
+
+ virtual void clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer);
+
+ virtual void markAllStateDirty();
+
+ // lost device
+ void notifyDeviceLost();
+ virtual bool isDeviceLost();
+ virtual bool testDeviceLost(bool notify);
+ virtual bool testDeviceResettable();
+
+ // Renderer capabilities
+ virtual DWORD getAdapterVendor() const;
+ virtual std::string getRendererDescription() const;
+ virtual GUID getAdapterIdentifier() const;
+
+ virtual bool getBGRATextureSupport() const;
+ virtual bool getDXT1TextureSupport();
+ virtual bool getDXT3TextureSupport();
+ virtual bool getDXT5TextureSupport();
+ virtual bool getEventQuerySupport();
+ virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable);
+ virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable);
+ virtual bool getLuminanceTextureSupport();
+ virtual bool getLuminanceAlphaTextureSupport();
+ virtual unsigned int getMaxVertexTextureImageUnits() const;
+ virtual unsigned int getMaxCombinedTextureImageUnits() const;
+ virtual unsigned int getReservedVertexUniformVectors() const;
+ virtual unsigned int getReservedFragmentUniformVectors() const;
+ virtual unsigned int getMaxVertexUniformVectors() const;
+ virtual unsigned int getMaxFragmentUniformVectors() const;
+ virtual unsigned int getMaxVaryingVectors() const;
+ virtual bool getNonPower2TextureSupport() const;
+ virtual bool getDepthTextureSupport() const;
+ virtual bool getOcclusionQuerySupport() const;
+ virtual bool getInstancingSupport() const;
+ virtual bool getTextureFilterAnisotropySupport() const;
+ virtual float getTextureMaxAnisotropy() const;
+ virtual bool getShareHandleSupport() const;
+ virtual bool getDerivativeInstructionSupport() const;
+ virtual bool getPostSubBufferSupport() const;
+
+ virtual int getMajorShaderModel() const;
+ virtual float getMaxPointSize() const;
+ virtual int getMaxViewportDimension() const;
+ virtual int getMaxTextureWidth() const;
+ virtual int getMaxTextureHeight() const;
+ virtual bool get32BitIndexSupport() const;
+ virtual int getMinSwapInterval() const;
+ virtual int getMaxSwapInterval() const;
+
+ virtual GLsizei getMaxSupportedSamples() const;
+ int getNearestSupportedSamples(DXGI_FORMAT format, unsigned int requested) const;
+
+ virtual unsigned int getMaxRenderTargets() const;
+
+ // Pixel operations
+ virtual bool copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source);
+ virtual bool copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source);
+
+ virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level);
+ virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level);
+
+ bool copyTexture(ID3D11ShaderResourceView *source, const gl::Rectangle &sourceArea, unsigned int sourceWidth, unsigned int sourceHeight,
+ ID3D11RenderTargetView *dest, const gl::Rectangle &destArea, unsigned int destWidth, unsigned int destHeight, GLenum destFormat);
+
+ virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect,
+ bool blitRenderTarget, bool blitDepthStencil);
+ virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels);
+
+ // RenderTarget creation
+ virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth);
+ virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth);
+
+ // Shader operations
+ virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type);
+ virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type);
+
+ // Image operations
+ virtual Image *createImage();
+ virtual void generateMipmap(Image *dest, Image *source);
+ virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain);
+ virtual TextureStorage *createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height);
+ virtual TextureStorage *createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size);
+
+ // Buffer creation
+ virtual VertexBuffer *createVertexBuffer();
+ virtual IndexBuffer *createIndexBuffer();
+ virtual BufferStorage *createBufferStorage();
+
+ // Query and Fence creation
+ virtual QueryImpl *createQuery(GLenum type);
+ virtual FenceImpl *createFence();
+
+ // D3D11-renderer specific methods
+ ID3D11Device *getDevice() { return mDevice; }
+ ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; };
+ IDXGIFactory *getDxgiFactory() { return mDxgiFactory; };
+
+ bool getRenderTargetResource(gl::Renderbuffer *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource);
+ void unapplyRenderTargets();
+ void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView);
+
+ virtual bool getLUID(LUID *adapterLuid) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Renderer11);
+
+ void drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
+ void drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances);
+
+ void readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area,
+ GLenum format, GLenum type, GLsizei outputPitch, bool packReverseRowOrder,
+ GLint packAlignment, void *pixels);
+
+ void maskedClear(const gl::ClearParameters &clearParams, bool usingExtendedDrawBuffers);
+ rx::Range getViewportBounds() const;
+
+ bool blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget,
+ RenderTarget *drawRenderTarget, bool wholeBufferCopy);
+ ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource);
+
+ HMODULE mD3d11Module;
+ HMODULE mDxgiModule;
+ HDC mDc;
+
+ bool mDeviceLost;
+
+ void initializeDevice();
+ void releaseDeviceResources();
+ int getMinorShaderModel() const;
+ void release();
+
+ RenderStateCache mStateCache;
+
+ // Support flags
+ bool mFloat16TextureSupport;
+ bool mFloat16FilterSupport;
+ bool mFloat16RenderSupport;
+
+ bool mFloat32TextureSupport;
+ bool mFloat32FilterSupport;
+ bool mFloat32RenderSupport;
+
+ bool mDXT1TextureSupport;
+ bool mDXT3TextureSupport;
+ bool mDXT5TextureSupport;
+
+ bool mDepthTextureSupport;
+
+ // Multisample format support
+ struct MultisampleSupportInfo
+ {
+ unsigned int qualityLevels[D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT];
+ };
+
+ typedef std::unordered_map<DXGI_FORMAT, MultisampleSupportInfo> MultisampleSupportMap;
+ MultisampleSupportMap mMultisampleSupportMap;
+
+ unsigned int mMaxSupportedSamples;
+
+ // current render target states
+ unsigned int mAppliedRenderTargetSerials[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS];
+ unsigned int mAppliedDepthbufferSerial;
+ unsigned int mAppliedStencilbufferSerial;
+ bool mDepthStencilInitialized;
+ bool mRenderTargetDescInitialized;
+ rx::RenderTarget::Desc mRenderTargetDesc;
+ unsigned int mCurDepthSize;
+ unsigned int mCurStencilSize;
+
+ // Currently applied sampler states
+ bool mForceSetVertexSamplerStates[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
+ gl::SamplerState mCurVertexSamplerStates[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
+
+ bool mForceSetPixelSamplerStates[gl::MAX_TEXTURE_IMAGE_UNITS];
+ gl::SamplerState mCurPixelSamplerStates[gl::MAX_TEXTURE_IMAGE_UNITS];
+
+ // Currently applied textures
+ unsigned int mCurVertexTextureSerials[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
+ unsigned int mCurPixelTextureSerials[gl::MAX_TEXTURE_IMAGE_UNITS];
+
+ // Currently applied blend state
+ bool mForceSetBlendState;
+ gl::BlendState mCurBlendState;
+ gl::Color mCurBlendColor;
+ unsigned int mCurSampleMask;
+
+ // Currently applied rasterizer state
+ bool mForceSetRasterState;
+ gl::RasterizerState mCurRasterState;
+
+ // Currently applied depth stencil state
+ bool mForceSetDepthStencilState;
+ gl::DepthStencilState mCurDepthStencilState;
+ int mCurStencilRef;
+ int mCurStencilBackRef;
+
+ // Currently applied scissor rectangle
+ bool mForceSetScissor;
+ bool mScissorEnabled;
+ gl::Rectangle mCurScissor;
+
+ // Currently applied viewport
+ bool mForceSetViewport;
+ gl::Rectangle mCurViewport;
+ float mCurNear;
+ float mCurFar;
+
+ // Currently applied primitive topology
+ D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology;
+
+ unsigned int mAppliedIBSerial;
+ unsigned int mAppliedStorageIBSerial;
+ unsigned int mAppliedIBOffset;
+
+ unsigned int mAppliedProgramBinarySerial;
+ bool mIsGeometryShaderActive;
+
+ dx_VertexConstants mVertexConstants;
+ dx_VertexConstants mAppliedVertexConstants;
+ ID3D11Buffer *mDriverConstantBufferVS;
+ ID3D11Buffer *mCurrentVertexConstantBuffer;
+
+ dx_PixelConstants mPixelConstants;
+ dx_PixelConstants mAppliedPixelConstants;
+ ID3D11Buffer *mDriverConstantBufferPS;
+ ID3D11Buffer *mCurrentPixelConstantBuffer;
+
+ ID3D11Buffer *mCurrentGeometryConstantBuffer;
+
+ // Vertex, index and input layouts
+ VertexDataManager *mVertexDataManager;
+ IndexDataManager *mIndexDataManager;
+ InputLayoutCache mInputLayoutCache;
+
+ StreamingIndexBufferInterface *mLineLoopIB;
+ StreamingIndexBufferInterface *mTriangleFanIB;
+
+ // Texture copy resources
+ bool mCopyResourcesInitialized;
+ ID3D11Buffer *mCopyVB;
+ ID3D11SamplerState *mCopySampler;
+ ID3D11InputLayout *mCopyIL;
+ ID3D11VertexShader *mCopyVS;
+ ID3D11PixelShader *mCopyRGBAPS;
+ ID3D11PixelShader *mCopyRGBPS;
+ ID3D11PixelShader *mCopyLumPS;
+ ID3D11PixelShader *mCopyLumAlphaPS;
+
+ // Masked clear resources
+ bool mClearResourcesInitialized;
+ ID3D11Buffer *mClearVB;
+ ID3D11InputLayout *mClearIL;
+ ID3D11VertexShader *mClearVS;
+ ID3D11PixelShader *mClearSinglePS;
+ ID3D11PixelShader *mClearMultiplePS;
+ ID3D11RasterizerState *mClearScissorRS;
+ ID3D11RasterizerState *mClearNoScissorRS;
+
+ // Sync query
+ ID3D11Query *mSyncQuery;
+
+ ID3D11Device *mDevice;
+ D3D_FEATURE_LEVEL mFeatureLevel;
+ ID3D11DeviceContext *mDeviceContext;
+ IDXGIAdapter *mDxgiAdapter;
+ DXGI_ADAPTER_DESC mAdapterDescription;
+ char mDescription[128];
+ IDXGIFactory *mDxgiFactory;
+
+ // Cached device caps
+ bool mBGRATextureSupport;
+};
+
+}
+#endif // LIBGLESV2_RENDERER_RENDERER11_H_
diff --git a/src/libGLESv2/renderer/Renderer9.cpp b/src/libGLESv2/renderer/Renderer9.cpp
new file mode 100644
index 00000000..240367d5
--- /dev/null
+++ b/src/libGLESv2/renderer/Renderer9.cpp
@@ -0,0 +1,3222 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer.
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/renderer/IndexDataManager.h"
+#include "libGLESv2/renderer/Renderer9.h"
+#include "libGLESv2/renderer/renderer9_utils.h"
+#include "libGLESv2/renderer/ShaderExecutable9.h"
+#include "libGLESv2/renderer/SwapChain9.h"
+#include "libGLESv2/renderer/TextureStorage9.h"
+#include "libGLESv2/renderer/Image9.h"
+#include "libGLESv2/renderer/Blit.h"
+#include "libGLESv2/renderer/RenderTarget9.h"
+#include "libGLESv2/renderer/VertexBuffer9.h"
+#include "libGLESv2/renderer/IndexBuffer9.h"
+#include "libGLESv2/renderer/BufferStorage9.h"
+#include "libGLESv2/renderer/Query9.h"
+#include "libGLESv2/renderer/Fence9.h"
+
+#include "libEGL/Display.h"
+
+// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
+#define REF_RAST 0
+
+// The "Debug This Pixel..." feature in PIX often fails when using the
+// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7
+// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file.
+#if !defined(ANGLE_ENABLE_D3D9EX)
+// Enables use of the IDirect3D9Ex interface, when available
+#define ANGLE_ENABLE_D3D9EX 1
+#endif // !defined(ANGLE_ENABLE_D3D9EX)
+
+namespace rx
+{
+static const D3DFORMAT RenderTargetFormats[] =
+ {
+ D3DFMT_A1R5G5B5,
+ // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
+ D3DFMT_A8R8G8B8,
+ D3DFMT_R5G6B5,
+ // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
+ D3DFMT_X8R8G8B8
+ };
+
+static const D3DFORMAT DepthStencilFormats[] =
+ {
+ D3DFMT_UNKNOWN,
+ // D3DFMT_D16_LOCKABLE,
+ D3DFMT_D32,
+ // D3DFMT_D15S1,
+ D3DFMT_D24S8,
+ D3DFMT_D24X8,
+ // D3DFMT_D24X4S4,
+ D3DFMT_D16,
+ // D3DFMT_D32F_LOCKABLE,
+ // D3DFMT_D24FS8
+ };
+
+enum
+{
+ MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256,
+ MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32,
+ MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224,
+ MAX_VARYING_VECTORS_SM2 = 8,
+ MAX_VARYING_VECTORS_SM3 = 10,
+
+ MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4
+};
+
+Renderer9::Renderer9(egl::Display *display, HDC hDc, bool softwareDevice) : Renderer(display), mDc(hDc), mSoftwareDevice(softwareDevice)
+{
+ mD3d9Module = NULL;
+
+ mD3d9 = NULL;
+ mD3d9Ex = NULL;
+ mDevice = NULL;
+ mDeviceEx = NULL;
+ mDeviceWindow = NULL;
+ mBlit = NULL;
+
+ mAdapter = D3DADAPTER_DEFAULT;
+
+ #if REF_RAST == 1 || defined(FORCE_REF_RAST)
+ mDeviceType = D3DDEVTYPE_REF;
+ #else
+ mDeviceType = D3DDEVTYPE_HAL;
+ #endif
+
+ mDeviceLost = false;
+
+ mMaxSupportedSamples = 0;
+
+ mMaskedClearSavedState = NULL;
+
+ mVertexDataManager = NULL;
+ mIndexDataManager = NULL;
+ mLineLoopIB = NULL;
+
+ mMaxNullColorbufferLRU = 0;
+ for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
+ {
+ mNullColorbufferCache[i].lruCount = 0;
+ mNullColorbufferCache[i].width = 0;
+ mNullColorbufferCache[i].height = 0;
+ mNullColorbufferCache[i].buffer = NULL;
+ }
+}
+
+Renderer9::~Renderer9()
+{
+ releaseDeviceResources();
+
+ if (mDevice)
+ {
+ // If the device is lost, reset it first to prevent leaving the driver in an unstable state
+ if (testDeviceLost(false))
+ {
+ resetDevice();
+ }
+
+ mDevice->Release();
+ mDevice = NULL;
+ }
+
+ if (mDeviceEx)
+ {
+ mDeviceEx->Release();
+ mDeviceEx = NULL;
+ }
+
+ if (mD3d9)
+ {
+ mD3d9->Release();
+ mD3d9 = NULL;
+ }
+
+ if (mDeviceWindow)
+ {
+ DestroyWindow(mDeviceWindow);
+ mDeviceWindow = NULL;
+ }
+
+ if (mD3d9Ex)
+ {
+ mD3d9Ex->Release();
+ mD3d9Ex = NULL;
+ }
+
+ if (mD3d9Module)
+ {
+ mD3d9Module = NULL;
+ }
+
+ while (!mMultiSampleSupport.empty())
+ {
+ delete [] mMultiSampleSupport.begin()->second;
+ mMultiSampleSupport.erase(mMultiSampleSupport.begin());
+ }
+}
+
+Renderer9 *Renderer9::makeRenderer9(Renderer *renderer)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(rx::Renderer9*, renderer));
+ return static_cast<rx::Renderer9*>(renderer);
+}
+
+EGLint Renderer9::initialize()
+{
+ if (!initializeCompiler())
+ {
+ return EGL_NOT_INITIALIZED;
+ }
+
+ if (mSoftwareDevice)
+ {
+ mD3d9Module = GetModuleHandle(TEXT("swiftshader_d3d9.dll"));
+ }
+ else
+ {
+ mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
+ }
+
+ if (mD3d9Module == NULL)
+ {
+ ERR("No D3D9 module found - aborting!\n");
+ return EGL_NOT_INITIALIZED;
+ }
+
+ typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
+ Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(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_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
+ {
+ ASSERT(mD3d9Ex);
+ mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
+ ASSERT(mD3d9);
+ }
+ else
+ {
+ mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
+ }
+
+ if (!mD3d9)
+ {
+ ERR("Could not create D3D9 device - aborting!\n");
+ return EGL_NOT_INITIALIZED;
+ }
+
+ if (mDc != NULL)
+ {
+ // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
+ }
+
+ HRESULT result;
+
+ // Give up on getting device caps after about one second.
+ for (int i = 0; i < 10; ++i)
+ {
+ result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
+ if (SUCCEEDED(result))
+ {
+ break;
+ }
+ else if (result == D3DERR_NOTAVAILABLE)
+ {
+ Sleep(100); // Give the driver some time to initialize/recover
+ }
+ else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
+ {
+ ERR("failed to get device caps (0x%x)\n", result);
+ return EGL_NOT_INITIALIZED;
+ }
+ }
+
+ if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
+ {
+ ERR("Renderer does not support PS 2.0. aborting!\n");
+ return EGL_NOT_INITIALIZED;
+ }
+
+ // 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::convertToRenderTarget.
+ if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
+ {
+ ERR("Renderer does not support stretctrect from textures!\n");
+ return EGL_NOT_INITIALIZED;
+ }
+
+ mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
+
+ // ATI cards on XP have problems with non-power-of-two textures.
+ mSupportsNonPower2Textures = !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
+ !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
+ !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) &&
+ !(getComparableOSVersion() < versionWindowsVista && mAdapterIdentifier.VendorId == VENDOR_ID_AMD);
+
+ // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec
+ mSupportsTextureFilterAnisotropy = ((mDeviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) && (mDeviceCaps.MaxAnisotropy >= 2));
+
+ mMinSwapInterval = 4;
+ mMaxSwapInterval = 0;
+
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE)
+ {
+ mMinSwapInterval = std::min(mMinSwapInterval, 0);
+ mMaxSwapInterval = std::max(mMaxSwapInterval, 0);
+ }
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE)
+ {
+ mMinSwapInterval = std::min(mMinSwapInterval, 1);
+ mMaxSwapInterval = std::max(mMaxSwapInterval, 1);
+ }
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO)
+ {
+ mMinSwapInterval = std::min(mMinSwapInterval, 2);
+ mMaxSwapInterval = std::max(mMaxSwapInterval, 2);
+ }
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE)
+ {
+ mMinSwapInterval = std::min(mMinSwapInterval, 3);
+ mMaxSwapInterval = std::max(mMaxSwapInterval, 3);
+ }
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR)
+ {
+ mMinSwapInterval = std::min(mMinSwapInterval, 4);
+ mMaxSwapInterval = std::max(mMaxSwapInterval, 4);
+ }
+
+ int max = 0;
+ for (unsigned int i = 0; i < ArraySize(RenderTargetFormats); ++i)
+ {
+ bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
+ getMultiSampleSupport(RenderTargetFormats[i], multisampleArray);
+ mMultiSampleSupport[RenderTargetFormats[i]] = multisampleArray;
+
+ for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
+ {
+ if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
+ {
+ max = j;
+ }
+ }
+ }
+
+ for (unsigned int i = 0; i < ArraySize(DepthStencilFormats); ++i)
+ {
+ if (DepthStencilFormats[i] == D3DFMT_UNKNOWN)
+ continue;
+
+ bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
+ getMultiSampleSupport(DepthStencilFormats[i], multisampleArray);
+ mMultiSampleSupport[DepthStencilFormats[i]] = multisampleArray;
+
+ for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
+ {
+ if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
+ {
+ max = j;
+ }
+ }
+ }
+
+ mMaxSupportedSamples = max;
+
+ static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
+ static const TCHAR className[] = TEXT("STATIC");
+
+ mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
+
+ D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
+ DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
+
+ 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_BAD_ALLOC;
+ }
+
+ if (FAILED(result))
+ {
+ 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_BAD_ALLOC;
+ }
+ }
+
+ if (mD3d9Ex)
+ {
+ result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
+ ASSERT(SUCCEEDED(result));
+ }
+
+ mVertexShaderCache.initialize(mDevice);
+ mPixelShaderCache.initialize(mDevice);
+
+ // Check occlusion query support
+ IDirect3DQuery9 *occlusionQuery = NULL;
+ if (SUCCEEDED(mDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery)
+ {
+ occlusionQuery->Release();
+ mOcclusionQuerySupport = true;
+ }
+ else
+ {
+ mOcclusionQuerySupport = false;
+ }
+
+ // Check event query support
+ IDirect3DQuery9 *eventQuery = NULL;
+ if (SUCCEEDED(mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery)
+ {
+ eventQuery->Release();
+ mEventQuerySupport = true;
+ }
+ else
+ {
+ mEventQuerySupport = false;
+ }
+
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ // Check vertex texture support
+ // Only Direct3D 10 ready devices support all the necessary vertex texture formats.
+ // We test this using D3D9 by checking support for the R16F format.
+ mVertexTextureSupport = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
+ D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F));
+
+ // Check depth texture support
+ // we use INTZ for depth textures in Direct3D9
+ // we also want NULL texture support to ensure the we can make depth-only FBOs
+ // see http://aras-p.info/texts/D3D9GPUHacks.html
+ mDepthTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
+ D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, D3DFMT_INTZ)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format,
+ D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL));
+
+ // Check 32 bit floating point texture support
+ mFloat32FilterSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
+
+ mFloat32RenderSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
+
+ if (!mFloat32FilterSupport && !mFloat32RenderSupport)
+ {
+ mFloat32TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
+ D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
+ }
+ else
+ {
+ mFloat32TextureSupport = true;
+ }
+
+ // Check 16 bit floating point texture support
+ mFloat16FilterSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
+
+ mFloat16RenderSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
+
+ if (!mFloat16FilterSupport && !mFloat16RenderSupport)
+ {
+ mFloat16TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
+ D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
+ }
+ else
+ {
+ mFloat16TextureSupport = true;
+ }
+
+ // Check DXT texture support
+ mDXT1TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
+ mDXT3TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT3));
+ mDXT5TextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT5));
+
+ // Check luminance[alpha] texture support
+ mLuminanceTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
+ mLuminanceAlphaTextureSupport = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
+
+ initializeDevice();
+
+ return EGL_SUCCESS;
+}
+
+// do any one-time device initialization
+// NOTE: this is also needed after a device lost/reset
+// to reset the scene status and ensure the default states are reset.
+void Renderer9::initializeDevice()
+{
+ // Permanent non-default states
+ mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE);
+
+ if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
+ {
+ mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD&)mDeviceCaps.MaxPointSize);
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000); // 1.0f
+ }
+
+ markAllStateDirty();
+
+ mSceneStarted = false;
+
+ ASSERT(!mBlit && !mVertexDataManager && !mIndexDataManager);
+ mBlit = new Blit(this);
+ mVertexDataManager = new rx::VertexDataManager(this);
+ mIndexDataManager = new rx::IndexDataManager(this);
+}
+
+D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters()
+{
+ D3DPRESENT_PARAMETERS presentParameters = {0};
+
+ // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
+ presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
+ presentParameters.BackBufferCount = 1;
+ presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
+ presentParameters.BackBufferWidth = 1;
+ presentParameters.BackBufferHeight = 1;
+ presentParameters.EnableAutoDepthStencil = FALSE;
+ presentParameters.Flags = 0;
+ presentParameters.hDeviceWindow = mDeviceWindow;
+ presentParameters.MultiSampleQuality = 0;
+ presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
+ presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+ presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ presentParameters.Windowed = TRUE;
+
+ return presentParameters;
+}
+
+int Renderer9::generateConfigs(ConfigDesc **configDescList)
+{
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ unsigned int numRenderFormats = ArraySize(RenderTargetFormats);
+ unsigned int numDepthFormats = ArraySize(DepthStencilFormats);
+ (*configDescList) = new ConfigDesc[numRenderFormats * numDepthFormats];
+ int numConfigs = 0;
+
+ for (unsigned int formatIndex = 0; formatIndex < numRenderFormats; formatIndex++)
+ {
+ D3DFORMAT renderTargetFormat = RenderTargetFormats[formatIndex];
+
+ HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat);
+
+ if (SUCCEEDED(result))
+ {
+ for (unsigned int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++)
+ {
+ D3DFORMAT depthStencilFormat = DepthStencilFormats[depthStencilIndex];
+ HRESULT result = D3D_OK;
+
+ if(depthStencilFormat != D3DFMT_UNKNOWN)
+ {
+ result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat);
+ }
+
+ if (SUCCEEDED(result))
+ {
+ if(depthStencilFormat != D3DFMT_UNKNOWN)
+ {
+ result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat);
+ }
+
+ if (SUCCEEDED(result))
+ {
+ ConfigDesc newConfig;
+ newConfig.renderTargetFormat = d3d9_gl::ConvertBackBufferFormat(renderTargetFormat);
+ newConfig.depthStencilFormat = d3d9_gl::ConvertDepthStencilFormat(depthStencilFormat);
+ newConfig.multiSample = 0; // FIXME: enumerate multi-sampling
+ newConfig.fastConfig = (currentDisplayMode.Format == renderTargetFormat);
+
+ (*configDescList)[numConfigs++] = newConfig;
+ }
+ }
+ }
+ }
+ }
+
+ return numConfigs;
+}
+
+void Renderer9::deleteConfigs(ConfigDesc *configDescList)
+{
+ delete [] (configDescList);
+}
+
+void Renderer9::startScene()
+{
+ if (!mSceneStarted)
+ {
+ long result = mDevice->BeginScene();
+ if (SUCCEEDED(result)) {
+ // This is defensive checking against the device being
+ // lost at unexpected times.
+ mSceneStarted = true;
+ }
+ }
+}
+
+void Renderer9::endScene()
+{
+ if (mSceneStarted)
+ {
+ // EndScene can fail if the device was lost, for example due
+ // to a TDR during a draw call.
+ mDevice->EndScene();
+ mSceneStarted = false;
+ }
+}
+
+void Renderer9::sync(bool block)
+{
+ HRESULT result;
+
+ IDirect3DQuery9* query = allocateEventQuery();
+ if (!query)
+ {
+ return;
+ }
+
+ result = query->Issue(D3DISSUE_END);
+ ASSERT(SUCCEEDED(result));
+
+ do
+ {
+ result = query->GetData(NULL, 0, D3DGETDATA_FLUSH);
+
+ if(block && result == S_FALSE)
+ {
+ // Keep polling, but allow other threads to do something useful first
+ Sleep(0);
+ // explicitly check for device loss
+ // some drivers seem to return S_FALSE even if the device is lost
+ // instead of D3DERR_DEVICELOST like they should
+ if (testDeviceLost(false))
+ {
+ result = D3DERR_DEVICELOST;
+ }
+ }
+ }
+ while(block && result == S_FALSE);
+
+ freeEventQuery(query);
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ notifyDeviceLost();
+ }
+}
+
+SwapChain *Renderer9::createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat)
+{
+ return new rx::SwapChain9(this, window, shareHandle, backBufferFormat, depthBufferFormat);
+}
+
+IDirect3DQuery9* Renderer9::allocateEventQuery()
+{
+ IDirect3DQuery9 *query = NULL;
+
+ if (mEventQueryPool.empty())
+ {
+ HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
+ ASSERT(SUCCEEDED(result));
+ }
+ else
+ {
+ query = mEventQueryPool.back();
+ mEventQueryPool.pop_back();
+ }
+
+ return query;
+}
+
+void Renderer9::freeEventQuery(IDirect3DQuery9* query)
+{
+ if (mEventQueryPool.size() > 1000)
+ {
+ query->Release();
+ }
+ else
+ {
+ mEventQueryPool.push_back(query);
+ }
+}
+
+IDirect3DVertexShader9 *Renderer9::createVertexShader(const DWORD *function, size_t length)
+{
+ return mVertexShaderCache.create(function, length);
+}
+
+IDirect3DPixelShader9 *Renderer9::createPixelShader(const DWORD *function, size_t length)
+{
+ return mPixelShaderCache.create(function, length);
+}
+
+HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer)
+{
+ D3DPOOL Pool = getBufferPool(Usage);
+ return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL);
+}
+
+VertexBuffer *Renderer9::createVertexBuffer()
+{
+ return new VertexBuffer9(this);
+}
+
+HRESULT Renderer9::createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer)
+{
+ D3DPOOL Pool = getBufferPool(Usage);
+ return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, NULL);
+}
+
+IndexBuffer *Renderer9::createIndexBuffer()
+{
+ return new IndexBuffer9(this);
+}
+
+BufferStorage *Renderer9::createBufferStorage()
+{
+ return new BufferStorage9();
+}
+
+QueryImpl *Renderer9::createQuery(GLenum type)
+{
+ return new Query9(this, type);
+}
+
+FenceImpl *Renderer9::createFence()
+{
+ return new Fence9(this);
+}
+
+void Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState)
+{
+ bool *forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates;
+ gl::SamplerState *appliedSamplers = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates: mCurVertexSamplerStates;
+
+ if (forceSetSamplers[index] || memcmp(&samplerState, &appliedSamplers[index], sizeof(gl::SamplerState)) != 0)
+ {
+ int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
+ int d3dSampler = index + d3dSamplerOffset;
+
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, gl_d3d9::ConvertTextureWrap(samplerState.wrapS));
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, gl_d3d9::ConvertTextureWrap(samplerState.wrapT));
+
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, gl_d3d9::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy));
+ D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
+ gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.lodOffset);
+ if (mSupportsTextureFilterAnisotropy)
+ {
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy);
+ }
+ }
+
+ forceSetSamplers[index] = false;
+ appliedSamplers[index] = samplerState;
+}
+
+void Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture)
+{
+ int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
+ int d3dSampler = index + d3dSamplerOffset;
+ IDirect3DBaseTexture9 *d3dTexture = NULL;
+ unsigned int serial = 0;
+ bool forceSetTexture = false;
+
+ unsigned int *appliedSerials = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextureSerials : mCurVertexTextureSerials;
+
+ if (texture)
+ {
+ TextureStorageInterface *texStorage = texture->getNativeTexture();
+ if (texStorage)
+ {
+ TextureStorage9 *storage9 = TextureStorage9::makeTextureStorage9(texStorage->getStorageInstance());
+ d3dTexture = storage9->getBaseTexture();
+ }
+ // If we get NULL back from getBaseTexture here, something went wrong
+ // in the texture class and we're unexpectedly missing the d3d texture
+ ASSERT(d3dTexture != NULL);
+
+ serial = texture->getTextureSerial();
+ forceSetTexture = texture->hasDirtyImages();
+ }
+
+ if (forceSetTexture || appliedSerials[index] != serial)
+ {
+ mDevice->SetTexture(d3dSampler, d3dTexture);
+ }
+
+ appliedSerials[index] = serial;
+}
+
+void Renderer9::setRasterizerState(const gl::RasterizerState &rasterState)
+{
+ bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0;
+
+ if (rasterStateChanged)
+ {
+ // Set the cull mode
+ if (rasterState.cullFace)
+ {
+ mDevice->SetRenderState(D3DRS_CULLMODE, gl_d3d9::ConvertCullMode(rasterState.cullMode, rasterState.frontFace));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ }
+
+ if (rasterState.polygonOffsetFill)
+ {
+ if (mCurDepthSize > 0)
+ {
+ mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&rasterState.polygonOffsetFactor);
+
+ float depthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(mCurDepthSize));
+ mDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&depthBias);
+ }
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
+ mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0);
+ }
+
+ mCurRasterState = rasterState;
+ }
+
+ mForceSetRasterState = false;
+}
+
+void Renderer9::setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor, unsigned int sampleMask)
+{
+ bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0;
+ bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::Color)) != 0;
+ bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask;
+
+ if (blendStateChanged || blendColorChanged)
+ {
+ if (blendState.blend)
+ {
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+ if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
+ blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
+ {
+ mDevice->SetRenderState(D3DRS_BLENDFACTOR, gl_d3d9::ConvertColor(blendColor));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha),
+ gl::unorm<8>(blendColor.alpha),
+ gl::unorm<8>(blendColor.alpha),
+ gl::unorm<8>(blendColor.alpha)));
+ }
+
+ mDevice->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB));
+ mDevice->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB));
+ mDevice->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB));
+
+ if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha ||
+ blendState.destBlendRGB != blendState.destBlendAlpha ||
+ blendState.blendEquationRGB != blendState.blendEquationAlpha)
+ {
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+
+ mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha));
+ mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha));
+ mDevice->SetRenderState(D3DRS_BLENDOPALPHA, gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+ }
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ }
+
+ if (blendState.sampleAlphaToCoverage)
+ {
+ FIXME("Sample alpha to coverage is unimplemented.");
+ }
+
+ // Set the color mask
+ bool zeroColorMaskAllowed = getAdapterVendor() != 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
+
+ DWORD colorMask = gl_d3d9::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen,
+ blendState.colorMaskBlue, blendState.colorMaskAlpha);
+ if (colorMask == 0 && !zeroColorMaskAllowed)
+ {
+ // Enable green channel, but set blending so nothing will be drawn.
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+ mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
+ mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
+ mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
+ }
+
+ mDevice->SetRenderState(D3DRS_DITHERENABLE, blendState.dither ? TRUE : FALSE);
+
+ mCurBlendState = blendState;
+ mCurBlendColor = blendColor;
+ }
+
+ if (sampleMaskChanged)
+ {
+ // Set the multisample mask
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast<DWORD>(sampleMask));
+
+ mCurSampleMask = sampleMask;
+ }
+
+ mForceSetBlendState = false;
+}
+
+void Renderer9::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
+ int stencilBackRef, bool frontFaceCCW)
+{
+ bool depthStencilStateChanged = mForceSetDepthStencilState ||
+ memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0;
+ bool stencilRefChanged = mForceSetDepthStencilState || stencilRef != mCurStencilRef ||
+ stencilBackRef != mCurStencilBackRef;
+ bool frontFaceCCWChanged = mForceSetDepthStencilState || frontFaceCCW != mCurFrontFaceCCW;
+
+ if (depthStencilStateChanged)
+ {
+ if (depthStencilState.depthTest)
+ {
+ mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
+ mDevice->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthStencilState.depthFunc));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
+ }
+
+ mCurDepthStencilState = depthStencilState;
+ }
+
+ if (depthStencilStateChanged || stencilRefChanged || frontFaceCCWChanged)
+ {
+ if (depthStencilState.stencilTest && mCurStencilSize > 0)
+ {
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
+
+ // FIXME: Unsupported by D3D9
+ const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
+ const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
+ const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
+ if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
+ stencilRef != stencilBackRef ||
+ depthStencilState.stencilMask != depthStencilState.stencilBackMask)
+ {
+ ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL.");
+ return gl::error(GL_INVALID_OPERATION);
+ }
+
+ // get the maximum size of the stencil ref
+ unsigned int maxStencil = (1 << mCurStencilSize) - 1;
+
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK,
+ depthStencilState.stencilWritemask);
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ gl_d3d9::ConvertComparison(depthStencilState.stencilFunc));
+
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
+ (stencilRef < (int)maxStencil) ? stencilRef : maxStencil);
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK,
+ depthStencilState.stencilMask);
+
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilFail));
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthFail));
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthPass));
+
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK,
+ depthStencilState.stencilBackWritemask);
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ gl_d3d9::ConvertComparison(depthStencilState.stencilBackFunc));
+
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
+ (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil);
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK,
+ depthStencilState.stencilBackMask);
+
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackFail));
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthFail));
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthPass));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ }
+
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, depthStencilState.depthMask ? TRUE : FALSE);
+
+ mCurStencilRef = stencilRef;
+ mCurStencilBackRef = stencilBackRef;
+ mCurFrontFaceCCW = frontFaceCCW;
+ }
+
+ mForceSetDepthStencilState = false;
+}
+
+void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled)
+{
+ bool scissorChanged = mForceSetScissor ||
+ memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 ||
+ enabled != mScissorEnabled;
+
+ if (scissorChanged)
+ {
+ if (enabled)
+ {
+ RECT rect;
+ rect.left = gl::clamp(scissor.x, 0, static_cast<int>(mRenderTargetDesc.width));
+ rect.top = gl::clamp(scissor.y, 0, static_cast<int>(mRenderTargetDesc.height));
+ rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(mRenderTargetDesc.width));
+ rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(mRenderTargetDesc.height));
+ mDevice->SetScissorRect(&rect);
+ }
+
+ mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, enabled ? TRUE : FALSE);
+
+ mScissorEnabled = enabled;
+ mCurScissor = scissor;
+ }
+
+ mForceSetScissor = false;
+}
+
+bool Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
+ bool ignoreViewport)
+{
+ gl::Rectangle actualViewport = viewport;
+ float actualZNear = gl::clamp01(zNear);
+ float actualZFar = gl::clamp01(zFar);
+ if (ignoreViewport)
+ {
+ actualViewport.x = 0;
+ actualViewport.y = 0;
+ actualViewport.width = mRenderTargetDesc.width;
+ actualViewport.height = mRenderTargetDesc.height;
+ actualZNear = 0.0f;
+ actualZFar = 1.0f;
+ }
+
+ D3DVIEWPORT9 dxViewport;
+ dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast<int>(mRenderTargetDesc.width));
+ dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast<int>(mRenderTargetDesc.height));
+ dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast<int>(mRenderTargetDesc.width) - static_cast<int>(dxViewport.X));
+ dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast<int>(mRenderTargetDesc.height) - static_cast<int>(dxViewport.Y));
+ dxViewport.MinZ = actualZNear;
+ dxViewport.MaxZ = actualZFar;
+
+ if (dxViewport.Width <= 0 || dxViewport.Height <= 0)
+ {
+ return false; // Nothing to render
+ }
+
+ bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 ||
+ actualZNear != mCurNear || actualZFar != mCurFar;
+ if (viewportChanged)
+ {
+ mDevice->SetViewport(&dxViewport);
+
+ mCurViewport = actualViewport;
+ mCurNear = actualZNear;
+ mCurFar = actualZFar;
+
+ dx_VertexConstants vc = {0};
+ dx_PixelConstants pc = {0};
+
+ vc.viewAdjust[0] = (float)((actualViewport.width - (int)dxViewport.Width) + 2 * (actualViewport.x - (int)dxViewport.X) - 1) / dxViewport.Width;
+ vc.viewAdjust[1] = (float)((actualViewport.height - (int)dxViewport.Height) + 2 * (actualViewport.y - (int)dxViewport.Y) - 1) / dxViewport.Height;
+ vc.viewAdjust[2] = (float)actualViewport.width / dxViewport.Width;
+ vc.viewAdjust[3] = (float)actualViewport.height / dxViewport.Height;
+
+ pc.viewCoords[0] = actualViewport.width * 0.5f;
+ pc.viewCoords[1] = actualViewport.height * 0.5f;
+ pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f);
+ pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f);
+
+ pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f;
+ pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f;
+ pc.depthFront[2] = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f);;
+
+ vc.depthRange[0] = actualZNear;
+ vc.depthRange[1] = actualZFar;
+ vc.depthRange[2] = actualZFar - actualZNear;
+
+ pc.depthRange[0] = actualZNear;
+ pc.depthRange[1] = actualZFar;
+ pc.depthRange[2] = actualZFar - actualZNear;
+
+ if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants)) != 0)
+ {
+ mVertexConstants = vc;
+ mDxUniformsDirty = true;
+ }
+
+ if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants)) != 0)
+ {
+ mPixelConstants = pc;
+ mDxUniformsDirty = true;
+ }
+ }
+
+ mForceSetViewport = false;
+ return true;
+}
+
+bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count)
+{
+ 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:
+ return gl::error(GL_INVALID_ENUM, false);
+ }
+
+ return mPrimitiveCount > 0;
+}
+
+
+gl::Renderbuffer *Renderer9::getNullColorbuffer(gl::Renderbuffer *depthbuffer)
+{
+ if (!depthbuffer)
+ {
+ ERR("Unexpected null depthbuffer for depth-only FBO.");
+ return NULL;
+ }
+
+ GLsizei width = depthbuffer->getWidth();
+ GLsizei height = depthbuffer->getHeight();
+
+ // search cached nullcolorbuffers
+ for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
+ {
+ if (mNullColorbufferCache[i].buffer != NULL &&
+ mNullColorbufferCache[i].width == width &&
+ mNullColorbufferCache[i].height == height)
+ {
+ mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU;
+ return mNullColorbufferCache[i].buffer;
+ }
+ }
+
+ gl::Renderbuffer *nullbuffer = new gl::Renderbuffer(this, 0, new gl::Colorbuffer(this, width, height, GL_NONE, 0));
+
+ // add nullbuffer to the cache
+ NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0];
+ for (int i = 1; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
+ {
+ if (mNullColorbufferCache[i].lruCount < oldest->lruCount)
+ {
+ oldest = &mNullColorbufferCache[i];
+ }
+ }
+
+ delete oldest->buffer;
+ oldest->buffer = nullbuffer;
+ oldest->lruCount = ++mMaxNullColorbufferLRU;
+ oldest->width = width;
+ oldest->height = height;
+
+ return nullbuffer;
+}
+
+bool Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer)
+{
+ // 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.
+ gl::Renderbuffer *renderbufferObject = NULL;
+ if (framebuffer->getColorbufferType(0) != GL_NONE)
+ {
+ renderbufferObject = framebuffer->getColorbuffer(0);
+ }
+ else
+ {
+ renderbufferObject = getNullColorbuffer(framebuffer->getDepthbuffer());
+ }
+ if (!renderbufferObject)
+ {
+ ERR("unable to locate renderbuffer for FBO.");
+ return false;
+ }
+
+ bool renderTargetChanged = false;
+ unsigned int renderTargetSerial = renderbufferObject->getSerial();
+ if (renderTargetSerial != mAppliedRenderTargetSerial)
+ {
+ // Apply the render target on the device
+ IDirect3DSurface9 *renderTargetSurface = NULL;
+
+ RenderTarget *renderTarget = renderbufferObject->getRenderTarget();
+ if (renderTarget)
+ {
+ renderTargetSurface = RenderTarget9::makeRenderTarget9(renderTarget)->getSurface();
+ }
+
+ if (!renderTargetSurface)
+ {
+ ERR("render target pointer unexpectedly null.");
+ return false; // Context must be lost
+ }
+
+ mDevice->SetRenderTarget(0, renderTargetSurface);
+ renderTargetSurface->Release();
+
+ mAppliedRenderTargetSerial = renderTargetSerial;
+ renderTargetChanged = true;
+ }
+
+ gl::Renderbuffer *depthStencil = NULL;
+ unsigned int depthbufferSerial = 0;
+ unsigned int stencilbufferSerial = 0;
+ if (framebuffer->getDepthbufferType() != GL_NONE)
+ {
+ depthStencil = framebuffer->getDepthbuffer();
+ if (!depthStencil)
+ {
+ ERR("Depth stencil pointer unexpectedly null.");
+ return false;
+ }
+
+ depthbufferSerial = depthStencil->getSerial();
+ }
+ else if (framebuffer->getStencilbufferType() != GL_NONE)
+ {
+ depthStencil = framebuffer->getStencilbuffer();
+ if (!depthStencil)
+ {
+ ERR("Depth stencil pointer unexpectedly null.");
+ return false;
+ }
+
+ stencilbufferSerial = depthStencil->getSerial();
+ }
+
+ if (depthbufferSerial != mAppliedDepthbufferSerial ||
+ stencilbufferSerial != mAppliedStencilbufferSerial ||
+ !mDepthStencilInitialized)
+ {
+ unsigned int depthSize = 0;
+ unsigned int stencilSize = 0;
+
+ // Apply the depth stencil on the device
+ if (depthStencil)
+ {
+ IDirect3DSurface9 *depthStencilSurface = NULL;
+ RenderTarget *depthStencilRenderTarget = depthStencil->getDepthStencil();
+
+ if (depthStencilRenderTarget)
+ {
+ depthStencilSurface = RenderTarget9::makeRenderTarget9(depthStencilRenderTarget)->getSurface();
+ }
+
+ if (!depthStencilSurface)
+ {
+ ERR("depth stencil pointer unexpectedly null.");
+ return false; // Context must be lost
+ }
+
+ mDevice->SetDepthStencilSurface(depthStencilSurface);
+ depthStencilSurface->Release();
+
+ depthSize = depthStencil->getDepthSize();
+ stencilSize = depthStencil->getStencilSize();
+ }
+ else
+ {
+ mDevice->SetDepthStencilSurface(NULL);
+ }
+
+ if (!mDepthStencilInitialized || depthSize != mCurDepthSize)
+ {
+ mCurDepthSize = depthSize;
+ mForceSetRasterState = true;
+ }
+
+ if (!mDepthStencilInitialized || stencilSize != mCurStencilSize)
+ {
+ mCurStencilSize = stencilSize;
+ mForceSetDepthStencilState = true;
+ }
+
+ mAppliedDepthbufferSerial = depthbufferSerial;
+ mAppliedStencilbufferSerial = stencilbufferSerial;
+ mDepthStencilInitialized = true;
+ }
+
+ if (renderTargetChanged || !mRenderTargetDescInitialized)
+ {
+ mForceSetScissor = true;
+ mForceSetViewport = true;
+
+ mRenderTargetDesc.width = renderbufferObject->getWidth();
+ mRenderTargetDesc.height = renderbufferObject->getHeight();
+ mRenderTargetDesc.format = renderbufferObject->getActualFormat();
+ mRenderTargetDescInitialized = true;
+ }
+
+ return true;
+}
+
+GLenum Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances)
+{
+ TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS];
+ GLenum err = mVertexDataManager->prepareVertexData(vertexAttributes, programBinary, first, count, attributes, instances);
+ if (err != GL_NO_ERROR)
+ {
+ return err;
+ }
+
+ return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, &mRepeatDraw);
+}
+
+// Applies the indices and element array bindings to the Direct3D 9 device
+GLenum Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
+{
+ GLenum err = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo);
+
+ if (err == GL_NO_ERROR)
+ {
+ // Directly binding the storage buffer is not supported for d3d9
+ ASSERT(indexInfo->storage == NULL);
+
+ if (indexInfo->serial != mAppliedIBSerial)
+ {
+ IndexBuffer9* indexBuffer = IndexBuffer9::makeIndexBuffer9(indexInfo->indexBuffer);
+
+ mDevice->SetIndices(indexBuffer->getBuffer());
+ mAppliedIBSerial = indexInfo->serial;
+ }
+ }
+
+ return err;
+}
+
+void Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances)
+{
+ startScene();
+
+ if (mode == GL_LINE_LOOP)
+ {
+ drawLineLoop(count, GL_NONE, NULL, 0, NULL);
+ }
+ else if (instances > 0)
+ {
+ StaticIndexBufferInterface *countingIB = mIndexDataManager->getCountingIndices(count);
+ if (countingIB)
+ {
+ if (mAppliedIBSerial != countingIB->getSerial())
+ {
+ IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(countingIB->getIndexBuffer());
+
+ mDevice->SetIndices(indexBuffer->getBuffer());
+ mAppliedIBSerial = countingIB->getSerial();
+ }
+
+ for (int i = 0; i < mRepeatDraw; i++)
+ {
+ mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount);
+ }
+ }
+ else
+ {
+ ERR("Could not create a counting index buffer for glDrawArraysInstanced.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+ else // Regular case
+ {
+ mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount);
+ }
+}
+
+void Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/)
+{
+ startScene();
+
+ if (mode == GL_POINTS)
+ {
+ drawIndexedPoints(count, type, indices, elementArrayBuffer);
+ }
+ else if (mode == GL_LINE_LOOP)
+ {
+ drawLineLoop(count, type, indices, indexInfo.minIndex, elementArrayBuffer);
+ }
+ else
+ {
+ for (int i = 0; i < mRepeatDraw; i++)
+ {
+ GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
+ mDevice->DrawIndexedPrimitive(mPrimitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, mPrimitiveCount);
+ }
+ }
+}
+
+void Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer)
+{
+ // Get the raw indices for an indexed draw
+ if (type != GL_NONE && elementArrayBuffer)
+ {
+ gl::Buffer *indexBuffer = elementArrayBuffer;
+ BufferStorage *storage = indexBuffer->getStorage();
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ indices = static_cast<const GLubyte*>(storage->getData()) + offset;
+ }
+
+ UINT startIndex = 0;
+
+ if (get32BitIndexSupport())
+ {
+ if (!mLineLoopIB)
+ {
+ mLineLoopIB = new StreamingIndexBufferInterface(this);
+ if (!mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
+ {
+ delete mLineLoopIB;
+ mLineLoopIB = NULL;
+
+ ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int)))
+ {
+ ERR("Could not create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ // Checked by Renderer9::applyPrimitiveType
+ ASSERT(count >= 0);
+
+ const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int);
+ if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT))
+ {
+ ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ void* mappedMemory = NULL;
+ int offset = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory);
+ if (offset == -1 || mappedMemory == NULL)
+ {
+ ERR("Could not map index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ startIndex = static_cast<UINT>(offset) / 4;
+ unsigned int *data = reinterpret_cast<unsigned int*>(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<const GLubyte*>(indices)[i];
+ }
+ data[count] = static_cast<const GLubyte*>(indices)[0];
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLushort*>(indices)[i];
+ }
+ data[count] = static_cast<const GLushort*>(indices)[0];
+ break;
+ case GL_UNSIGNED_INT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLuint*>(indices)[i];
+ }
+ data[count] = static_cast<const GLuint*>(indices)[0];
+ break;
+ default: UNREACHABLE();
+ }
+
+ if (!mLineLoopIB->unmapBuffer())
+ {
+ ERR("Could not unmap index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+ else
+ {
+ if (!mLineLoopIB)
+ {
+ mLineLoopIB = new StreamingIndexBufferInterface(this);
+ if (!mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
+ {
+ delete mLineLoopIB;
+ mLineLoopIB = NULL;
+
+ ERR("Could not create a 16-bit looping index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ // Checked by Renderer9::applyPrimitiveType
+ ASSERT(count >= 0);
+
+ if (static_cast<unsigned int>(count) + 1 > (std::numeric_limits<unsigned short>::max() / sizeof(unsigned short)))
+ {
+ ERR("Could not create a 16-bit looping index buffer for GL_LINE_LOOP, too many indices required.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ const unsigned int spaceNeeded = (static_cast<unsigned int>(count) + 1) * sizeof(unsigned short);
+ if (!mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT))
+ {
+ ERR("Could not reserve enough space in looping index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ void* mappedMemory = NULL;
+ int offset = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory);
+ if (offset == -1 || mappedMemory == NULL)
+ {
+ ERR("Could not map index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ startIndex = static_cast<UINT>(offset) / 2;
+ unsigned short *data = reinterpret_cast<unsigned short*>(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<const GLubyte*>(indices)[i];
+ }
+ data[count] = static_cast<const GLubyte*>(indices)[0];
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLushort*>(indices)[i];
+ }
+ data[count] = static_cast<const GLushort*>(indices)[0];
+ break;
+ case GL_UNSIGNED_INT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLuint*>(indices)[i];
+ }
+ data[count] = static_cast<const GLuint*>(indices)[0];
+ break;
+ default: UNREACHABLE();
+ }
+
+ if (!mLineLoopIB->unmapBuffer())
+ {
+ ERR("Could not unmap index buffer for GL_LINE_LOOP.");
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ if (mAppliedIBSerial != mLineLoopIB->getSerial())
+ {
+ IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(mLineLoopIB->getIndexBuffer());
+
+ mDevice->SetIndices(indexBuffer->getBuffer());
+ mAppliedIBSerial = mLineLoopIB->getSerial();
+ }
+
+ mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count);
+}
+
+template <typename T>
+static void drawPoints(IDirect3DDevice9* device, GLsizei count, const GLvoid *indices)
+{
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int indexValue = static_cast<unsigned int>(static_cast<const T*>(indices)[i]);
+ device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1);
+ }
+}
+
+void Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer)
+{
+ // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call
+ // for each individual point. This call is not expected to happen often.
+
+ if (elementArrayBuffer)
+ {
+ BufferStorage *storage = elementArrayBuffer->getStorage();
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ indices = static_cast<const GLubyte*>(storage->getData()) + offset;
+ }
+
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: drawPoints<GLubyte>(mDevice, count, indices); break;
+ case GL_UNSIGNED_SHORT: drawPoints<GLushort>(mDevice, count, indices); break;
+ case GL_UNSIGNED_INT: drawPoints<GLuint>(mDevice, count, indices); break;
+ default: UNREACHABLE();
+ }
+}
+
+void Renderer9::applyShaders(gl::ProgramBinary *programBinary)
+{
+ unsigned int programBinarySerial = programBinary->getSerial();
+ if (programBinarySerial != mAppliedProgramBinarySerial)
+ {
+ ShaderExecutable *vertexExe = programBinary->getVertexExecutable();
+ ShaderExecutable *pixelExe = programBinary->getPixelExecutable();
+
+ IDirect3DVertexShader9 *vertexShader = NULL;
+ if (vertexExe) vertexShader = ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader();
+
+ IDirect3DPixelShader9 *pixelShader = NULL;
+ if (pixelExe) pixelShader = ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader();
+
+ mDevice->SetPixelShader(pixelShader);
+ mDevice->SetVertexShader(vertexShader);
+ programBinary->dirtyAllUniforms();
+ mDxUniformsDirty = true;
+
+ mAppliedProgramBinarySerial = programBinarySerial;
+ }
+}
+
+void Renderer9::applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray)
+{
+ for (std::vector<gl::Uniform*>::const_iterator ub = uniformArray->begin(), ue = uniformArray->end(); ub != ue; ++ub)
+ {
+ gl::Uniform *targetUniform = *ub;
+
+ if (targetUniform->dirty)
+ {
+ GLfloat *f = (GLfloat*)targetUniform->data;
+ GLint *i = (GLint*)targetUniform->data;
+
+ switch (targetUniform->type)
+ {
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ break;
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ applyUniformnbv(targetUniform, i);
+ break;
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT4:
+ applyUniformnfv(targetUniform, f);
+ break;
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ applyUniformniv(targetUniform, i);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ targetUniform->dirty = false;
+ }
+ }
+
+ // Driver uniforms
+ if (mDxUniformsDirty)
+ {
+ mDevice->SetVertexShaderConstantF(0, (float*)&mVertexConstants, sizeof(dx_VertexConstants) / sizeof(float[4]));
+ mDevice->SetPixelShaderConstantF(0, (float*)&mPixelConstants, sizeof(dx_PixelConstants) / sizeof(float[4]));
+ mDxUniformsDirty = false;
+ }
+}
+
+void Renderer9::applyUniformnfv(gl::Uniform *targetUniform, const GLfloat *v)
+{
+ if (targetUniform->psRegisterIndex >= 0)
+ {
+ mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount);
+ }
+
+ if (targetUniform->vsRegisterIndex >= 0)
+ {
+ mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount);
+ }
+}
+
+void Renderer9::applyUniformniv(gl::Uniform *targetUniform, const GLint *v)
+{
+ ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
+ GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
+
+ for (unsigned int i = 0; i < targetUniform->registerCount; i++)
+ {
+ vector[i][0] = (GLfloat)v[4 * i + 0];
+ vector[i][1] = (GLfloat)v[4 * i + 1];
+ vector[i][2] = (GLfloat)v[4 * i + 2];
+ vector[i][3] = (GLfloat)v[4 * i + 3];
+ }
+
+ applyUniformnfv(targetUniform, (GLfloat*)vector);
+}
+
+void Renderer9::applyUniformnbv(gl::Uniform *targetUniform, const GLint *v)
+{
+ ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
+ GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
+
+ for (unsigned int i = 0; i < targetUniform->registerCount; i++)
+ {
+ vector[i][0] = (v[4 * i + 0] == GL_FALSE) ? 0.0f : 1.0f;
+ vector[i][1] = (v[4 * i + 1] == GL_FALSE) ? 0.0f : 1.0f;
+ vector[i][2] = (v[4 * i + 2] == GL_FALSE) ? 0.0f : 1.0f;
+ vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f;
+ }
+
+ applyUniformnfv(targetUniform, (GLfloat*)vector);
+}
+
+void Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer)
+{
+ D3DCOLOR color = D3DCOLOR_ARGB(gl::unorm<8>(clearParams.colorClearValue.alpha),
+ gl::unorm<8>(clearParams.colorClearValue.red),
+ gl::unorm<8>(clearParams.colorClearValue.green),
+ gl::unorm<8>(clearParams.colorClearValue.blue));
+ float depth = gl::clamp01(clearParams.depthClearValue);
+ int stencil = clearParams.stencilClearValue & 0x000000FF;
+
+ unsigned int stencilUnmasked = 0x0;
+ if ((clearParams.mask & GL_STENCIL_BUFFER_BIT) && frameBuffer->hasStencil())
+ {
+ unsigned int stencilSize = gl::GetStencilSize(frameBuffer->getStencilbuffer()->getActualFormat());
+ stencilUnmasked = (0x1 << stencilSize) - 1;
+ }
+
+ bool alphaUnmasked = (gl::GetAlphaSize(mRenderTargetDesc.format) == 0) || clearParams.colorMaskAlpha;
+
+ const bool needMaskedStencilClear = (clearParams.mask & GL_STENCIL_BUFFER_BIT) &&
+ (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
+ const bool needMaskedColorClear = (clearParams.mask & GL_COLOR_BUFFER_BIT) &&
+ !(clearParams.colorMaskRed && clearParams.colorMaskGreen &&
+ clearParams.colorMaskBlue && alphaUnmasked);
+
+ if (needMaskedColorClear || needMaskedStencilClear)
+ {
+ // State which is altered in all paths from this point to the clear call is saved.
+ // State which is altered in only some paths will be flagged dirty in the case that
+ // that path is taken.
+ HRESULT hr;
+ if (mMaskedClearSavedState == NULL)
+ {
+ hr = mDevice->BeginStateBlock();
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+ mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ mDevice->SetPixelShader(NULL);
+ mDevice->SetVertexShader(NULL);
+ mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
+ mDevice->SetStreamSource(0, NULL, 0, 0);
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+ mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+ for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDevice->SetStreamSourceFreq(i, 1);
+ }
+
+ hr = mDevice->EndStateBlock(&mMaskedClearSavedState);
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+ }
+
+ ASSERT(mMaskedClearSavedState != NULL);
+
+ if (mMaskedClearSavedState != NULL)
+ {
+ hr = mMaskedClearSavedState->Capture();
+ ASSERT(SUCCEEDED(hr));
+ }
+
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+ mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+
+ if (clearParams.mask & GL_COLOR_BUFFER_BIT)
+ {
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
+ gl_d3d9::ConvertColorMask(clearParams.colorMaskRed,
+ clearParams.colorMaskGreen,
+ clearParams.colorMaskBlue,
+ clearParams.colorMaskAlpha));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+ }
+
+ if (stencilUnmasked != 0x0 && (clearParams.mask & GL_STENCIL_BUFFER_BIT))
+ {
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+ mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
+ mDevice->SetRenderState(D3DRS_STENCILREF, stencil);
+ mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, clearParams.stencilWriteMask);
+ mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
+ mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
+ mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ }
+
+ mDevice->SetPixelShader(NULL);
+ mDevice->SetVertexShader(NULL);
+ mDevice->SetFVF(D3DFVF_XYZRHW);
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+ mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+ for(int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDevice->SetStreamSourceFreq(i, 1);
+ }
+
+ float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges
+ quad[0][0] = -0.5f;
+ quad[0][1] = mRenderTargetDesc.height - 0.5f;
+ quad[0][2] = 0.0f;
+ quad[0][3] = 1.0f;
+
+ quad[1][0] = mRenderTargetDesc.width - 0.5f;
+ quad[1][1] = mRenderTargetDesc.height - 0.5f;
+ quad[1][2] = 0.0f;
+ quad[1][3] = 1.0f;
+
+ quad[2][0] = -0.5f;
+ quad[2][1] = -0.5f;
+ quad[2][2] = 0.0f;
+ quad[2][3] = 1.0f;
+
+ quad[3][0] = mRenderTargetDesc.width - 0.5f;
+ quad[3][1] = -0.5f;
+ quad[3][2] = 0.0f;
+ quad[3][3] = 1.0f;
+
+ startScene();
+ mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4]));
+
+ if (clearParams.mask & GL_DEPTH_BUFFER_BIT)
+ {
+ mDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
+ mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
+ }
+
+ if (mMaskedClearSavedState != NULL)
+ {
+ mMaskedClearSavedState->Apply();
+ }
+ }
+ else if (clearParams.mask)
+ {
+ DWORD dxClearFlags = 0;
+ if (clearParams.mask & GL_COLOR_BUFFER_BIT)
+ {
+ dxClearFlags |= D3DCLEAR_TARGET;
+ }
+ if (clearParams.mask & GL_DEPTH_BUFFER_BIT)
+ {
+ dxClearFlags |= D3DCLEAR_ZBUFFER;
+ }
+ if (clearParams.mask & GL_STENCIL_BUFFER_BIT)
+ {
+ dxClearFlags |= D3DCLEAR_STENCIL;
+ }
+
+ mDevice->Clear(0, NULL, dxClearFlags, color, depth, stencil);
+ }
+}
+
+void Renderer9::markAllStateDirty()
+{
+ mAppliedRenderTargetSerial = 0;
+ mAppliedDepthbufferSerial = 0;
+ mAppliedStencilbufferSerial = 0;
+ mDepthStencilInitialized = false;
+ mRenderTargetDescInitialized = false;
+
+ mForceSetDepthStencilState = true;
+ mForceSetRasterState = true;
+ mForceSetScissor = true;
+ mForceSetViewport = true;
+ mForceSetBlendState = true;
+
+ for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; i++)
+ {
+ mForceSetVertexSamplerStates[i] = true;
+ mCurVertexTextureSerials[i] = 0;
+ }
+ for (unsigned int i = 0; i < gl::MAX_TEXTURE_IMAGE_UNITS; i++)
+ {
+ mForceSetPixelSamplerStates[i] = true;
+ mCurPixelTextureSerials[i] = 0;
+ }
+
+ mAppliedIBSerial = 0;
+ mAppliedProgramBinarySerial = 0;
+ mDxUniformsDirty = true;
+
+ mVertexDeclarationCache.markStateDirty();
+}
+
+void Renderer9::releaseDeviceResources()
+{
+ while (!mEventQueryPool.empty())
+ {
+ mEventQueryPool.back()->Release();
+ mEventQueryPool.pop_back();
+ }
+
+ if (mMaskedClearSavedState)
+ {
+ mMaskedClearSavedState->Release();
+ mMaskedClearSavedState = NULL;
+ }
+
+ mVertexShaderCache.clear();
+ mPixelShaderCache.clear();
+
+ delete mBlit;
+ mBlit = NULL;
+
+ delete mVertexDataManager;
+ mVertexDataManager = NULL;
+
+ delete mIndexDataManager;
+ mIndexDataManager = NULL;
+
+ delete mLineLoopIB;
+ mLineLoopIB = NULL;
+
+ for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
+ {
+ delete mNullColorbufferCache[i].buffer;
+ mNullColorbufferCache[i].buffer = NULL;
+ }
+
+}
+
+
+void Renderer9::notifyDeviceLost()
+{
+ mDeviceLost = true;
+ mDisplay->notifyDeviceLost();
+}
+
+bool Renderer9::isDeviceLost()
+{
+ return mDeviceLost;
+}
+
+// set notify to true to broadcast a message to all contexts of the device loss
+bool Renderer9::testDeviceLost(bool notify)
+{
+ HRESULT status = S_OK;
+
+ if (mDeviceEx)
+ {
+ status = mDeviceEx->CheckDeviceState(NULL);
+ }
+ else if (mDevice)
+ {
+ status = mDevice->TestCooperativeLevel();
+ }
+ else
+ {
+ // No device yet, so no reset required
+ }
+
+ bool isLost = FAILED(status) || d3d9::isDeviceLostError(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;
+ if (notify)
+ {
+ notifyDeviceLost();
+ }
+ }
+
+ return isLost;
+}
+
+bool Renderer9::testDeviceResettable()
+{
+ HRESULT status = D3D_OK;
+
+ if (mDeviceEx)
+ {
+ status = mDeviceEx->CheckDeviceState(NULL);
+ }
+ else if (mDevice)
+ {
+ status = mDevice->TestCooperativeLevel();
+ }
+
+ // On D3D9Ex, DEVICELOST represents a hung device that needs to be restarted
+ // DEVICEREMOVED indicates the device has been stopped and must be recreated
+ switch (status)
+ {
+ case D3DERR_DEVICENOTRESET:
+ case D3DERR_DEVICEHUNG:
+ return true;
+ case D3DERR_DEVICELOST:
+ return (mDeviceEx != NULL);
+ case D3DERR_DEVICEREMOVED:
+ UNIMPLEMENTED();
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool Renderer9::resetDevice()
+{
+ releaseDeviceResources();
+
+ D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
+
+ HRESULT result = D3D_OK;
+ bool lost = testDeviceLost(false);
+ int attempts = 3;
+
+ while (lost && attempts > 0)
+ {
+ if (mDeviceEx)
+ {
+ Sleep(500); // Give the graphics driver some CPU time
+ result = mDeviceEx->ResetEx(&presentParameters, NULL);
+ }
+ else
+ {
+ result = mDevice->TestCooperativeLevel();
+ while (result == D3DERR_DEVICELOST)
+ {
+ Sleep(100); // Give the graphics driver some CPU time
+ result = mDevice->TestCooperativeLevel();
+ }
+
+ if (result == D3DERR_DEVICENOTRESET)
+ {
+ result = mDevice->Reset(&presentParameters);
+ }
+ }
+
+ lost = testDeviceLost(false);
+ attempts --;
+ }
+
+ if (FAILED(result))
+ {
+ ERR("Reset/ResetEx failed multiple times: 0x%08X", result);
+ return false;
+ }
+
+ // reset device defaults
+ initializeDevice();
+ mDeviceLost = false;
+
+ return true;
+}
+
+DWORD Renderer9::getAdapterVendor() const
+{
+ return mAdapterIdentifier.VendorId;
+}
+
+std::string Renderer9::getRendererDescription() const
+{
+ std::ostringstream rendererString;
+
+ rendererString << mAdapterIdentifier.Description;
+ if (getShareHandleSupport())
+ {
+ rendererString << " Direct3D9Ex";
+ }
+ else
+ {
+ rendererString << " Direct3D9";
+ }
+
+ rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion);
+ rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion);
+
+ return rendererString.str();
+}
+
+GUID Renderer9::getAdapterIdentifier() const
+{
+ return mAdapterIdentifier.DeviceIdentifier;
+}
+
+void Renderer9::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
+{
+ for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
+ {
+ HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
+ TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
+
+ multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
+ }
+}
+
+bool Renderer9::getBGRATextureSupport() const
+{
+ // DirectX 9 always supports BGRA
+ return true;
+}
+
+bool Renderer9::getDXT1TextureSupport()
+{
+ return mDXT1TextureSupport;
+}
+
+bool Renderer9::getDXT3TextureSupport()
+{
+ return mDXT3TextureSupport;
+}
+
+bool Renderer9::getDXT5TextureSupport()
+{
+ return mDXT5TextureSupport;
+}
+
+bool Renderer9::getDepthTextureSupport() const
+{
+ return mDepthTextureSupport;
+}
+
+bool Renderer9::getFloat32TextureSupport(bool *filtering, bool *renderable)
+{
+ *filtering = mFloat32FilterSupport;
+ *renderable = mFloat32RenderSupport;
+ return mFloat32TextureSupport;
+}
+
+bool Renderer9::getFloat16TextureSupport(bool *filtering, bool *renderable)
+{
+ *filtering = mFloat16FilterSupport;
+ *renderable = mFloat16RenderSupport;
+ return mFloat16TextureSupport;
+}
+
+bool Renderer9::getLuminanceTextureSupport()
+{
+ return mLuminanceTextureSupport;
+}
+
+bool Renderer9::getLuminanceAlphaTextureSupport()
+{
+ return mLuminanceAlphaTextureSupport;
+}
+
+bool Renderer9::getTextureFilterAnisotropySupport() const
+{
+ return mSupportsTextureFilterAnisotropy;
+}
+
+float Renderer9::getTextureMaxAnisotropy() const
+{
+ if (mSupportsTextureFilterAnisotropy)
+ {
+ return static_cast<float>(mDeviceCaps.MaxAnisotropy);
+ }
+ return 1.0f;
+}
+
+bool Renderer9::getEventQuerySupport()
+{
+ return mEventQuerySupport;
+}
+
+unsigned int Renderer9::getMaxVertexTextureImageUnits() const
+{
+ META_ASSERT(MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 <= gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+ return mVertexTextureSupport ? MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 : 0;
+}
+
+unsigned int Renderer9::getMaxCombinedTextureImageUnits() const
+{
+ return gl::MAX_TEXTURE_IMAGE_UNITS + getMaxVertexTextureImageUnits();
+}
+
+unsigned int Renderer9::getReservedVertexUniformVectors() const
+{
+ return 2; // dx_ViewAdjust and dx_DepthRange.
+}
+
+unsigned int Renderer9::getReservedFragmentUniformVectors() const
+{
+ return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange.
+}
+
+unsigned int Renderer9::getMaxVertexUniformVectors() const
+{
+ return MAX_VERTEX_CONSTANT_VECTORS_D3D9 - getReservedVertexUniformVectors();
+}
+
+unsigned int Renderer9::getMaxFragmentUniformVectors() const
+{
+ const int maxPixelConstantVectors = (getMajorShaderModel() >= 3) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 : MAX_PIXEL_CONSTANT_VECTORS_SM2;
+
+ return maxPixelConstantVectors - getReservedFragmentUniformVectors();
+}
+
+unsigned int Renderer9::getMaxVaryingVectors() const
+{
+ return (getMajorShaderModel() >= 3) ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2;
+}
+
+bool Renderer9::getNonPower2TextureSupport() const
+{
+ return mSupportsNonPower2Textures;
+}
+
+bool Renderer9::getOcclusionQuerySupport() const
+{
+ return mOcclusionQuerySupport;
+}
+
+bool Renderer9::getInstancingSupport() const
+{
+ return mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
+}
+
+bool Renderer9::getShareHandleSupport() const
+{
+ // PIX doesn't seem to support using share handles, so disable them.
+ return (mD3d9Ex != NULL) && !gl::perfActive();
+}
+
+bool Renderer9::getDerivativeInstructionSupport() const
+{
+ return (mDeviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0;
+}
+
+bool Renderer9::getPostSubBufferSupport() const
+{
+ return true;
+}
+
+int Renderer9::getMajorShaderModel() const
+{
+ return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion);
+}
+
+float Renderer9::getMaxPointSize() const
+{
+ // Point size clamped at 1.0f for SM2
+ return getMajorShaderModel() == 3 ? mDeviceCaps.MaxPointSize : 1.0f;
+}
+
+int Renderer9::getMaxViewportDimension() const
+{
+ int maxTextureDimension = std::min(std::min(getMaxTextureWidth(), getMaxTextureHeight()),
+ (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE);
+ return maxTextureDimension;
+}
+
+int Renderer9::getMaxTextureWidth() const
+{
+ return (int)mDeviceCaps.MaxTextureWidth;
+}
+
+int Renderer9::getMaxTextureHeight() const
+{
+ return (int)mDeviceCaps.MaxTextureHeight;
+}
+
+bool Renderer9::get32BitIndexSupport() const
+{
+ return mDeviceCaps.MaxVertexIndex >= (1 << 16);
+}
+
+DWORD Renderer9::getCapsDeclTypes() const
+{
+ return mDeviceCaps.DeclTypes;
+}
+
+int Renderer9::getMinSwapInterval() const
+{
+ return mMinSwapInterval;
+}
+
+int Renderer9::getMaxSwapInterval() const
+{
+ return mMaxSwapInterval;
+}
+
+int Renderer9::getMaxSupportedSamples() const
+{
+ return mMaxSupportedSamples;
+}
+
+int Renderer9::getNearestSupportedSamples(D3DFORMAT format, int requested) const
+{
+ if (requested == 0)
+ {
+ return requested;
+ }
+
+ std::map<D3DFORMAT, bool *>::const_iterator itr = mMultiSampleSupport.find(format);
+ if (itr == mMultiSampleSupport.end())
+ {
+ if (format == D3DFMT_UNKNOWN)
+ return 0;
+ return -1;
+ }
+
+ for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i)
+ {
+ if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+unsigned int Renderer9::getMaxRenderTargets() const
+{
+ // we do not support MRT in d3d9
+ return 1;
+}
+
+D3DFORMAT Renderer9::ConvertTextureInternalFormat(GLint internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_DEPTH_COMPONENT16:
+ case GL_DEPTH_COMPONENT32_OES:
+ case GL_DEPTH24_STENCIL8_OES:
+ return D3DFMT_INTZ;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ return D3DFMT_DXT1;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ return D3DFMT_DXT3;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ return D3DFMT_DXT5;
+ case GL_RGBA32F_EXT:
+ case GL_RGB32F_EXT:
+ case GL_ALPHA32F_EXT:
+ case GL_LUMINANCE32F_EXT:
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ return D3DFMT_A32B32G32R32F;
+ case GL_RGBA16F_EXT:
+ case GL_RGB16F_EXT:
+ case GL_ALPHA16F_EXT:
+ case GL_LUMINANCE16F_EXT:
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ return D3DFMT_A16B16G16R16F;
+ case GL_LUMINANCE8_EXT:
+ if (getLuminanceTextureSupport())
+ {
+ return D3DFMT_L8;
+ }
+ break;
+ case GL_LUMINANCE8_ALPHA8_EXT:
+ if (getLuminanceAlphaTextureSupport())
+ {
+ return D3DFMT_A8L8;
+ }
+ break;
+ case GL_RGB8_OES:
+ case GL_RGB565:
+ return D3DFMT_X8R8G8B8;
+ }
+
+ return D3DFMT_A8R8G8B8;
+}
+
+bool Renderer9::copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source)
+{
+ bool result = false;
+
+ if (source && dest)
+ {
+ TextureStorage9_2D *source9 = TextureStorage9_2D::makeTextureStorage9_2D(source->getStorageInstance());
+ TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(dest->getStorageInstance());
+
+ int levels = source9->levelCount();
+ for (int i = 0; i < levels; ++i)
+ {
+ IDirect3DSurface9 *srcSurf = source9->getSurfaceLevel(i, false);
+ IDirect3DSurface9 *dstSurf = dest9->getSurfaceLevel(i, false);
+
+ result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged());
+
+ if (srcSurf) srcSurf->Release();
+ if (dstSurf) dstSurf->Release();
+
+ if (!result)
+ return false;
+ }
+ }
+
+ return result;
+}
+
+bool Renderer9::copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source)
+{
+ bool result = false;
+
+ if (source && dest)
+ {
+ TextureStorage9_Cube *source9 = TextureStorage9_Cube::makeTextureStorage9_Cube(source->getStorageInstance());
+ TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(dest->getStorageInstance());
+ int levels = source9->levelCount();
+ for (int f = 0; f < 6; f++)
+ {
+ for (int i = 0; i < levels; i++)
+ {
+ IDirect3DSurface9 *srcSurf = source9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false);
+ IDirect3DSurface9 *dstSurf = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true);
+
+ result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged());
+
+ if (srcSurf) srcSurf->Release();
+ if (dstSurf) dstSurf->Release();
+
+ if (!result)
+ return false;
+ }
+ }
+ }
+
+ return result;
+}
+
+D3DPOOL Renderer9::getBufferPool(DWORD usage) const
+{
+ if (mD3d9Ex != NULL)
+ {
+ return D3DPOOL_DEFAULT;
+ }
+ else
+ {
+ if (!(usage & D3DUSAGE_DYNAMIC))
+ {
+ return D3DPOOL_MANAGED;
+ }
+ }
+
+ return D3DPOOL_DEFAULT;
+}
+
+bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level)
+{
+ RECT rect;
+ rect.left = sourceRect.x;
+ rect.top = sourceRect.y;
+ rect.right = sourceRect.x + sourceRect.width;
+ rect.bottom = sourceRect.y + sourceRect.height;
+
+ return mBlit->copy(framebuffer, rect, destFormat, xoffset, yoffset, storage, level);
+}
+
+bool Renderer9::copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level)
+{
+ RECT rect;
+ rect.left = sourceRect.x;
+ rect.top = sourceRect.y;
+ rect.right = sourceRect.x + sourceRect.width;
+ rect.bottom = sourceRect.y + sourceRect.height;
+
+ return mBlit->copy(framebuffer, rect, destFormat, xoffset, yoffset, storage, target, level);
+}
+
+bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &readRect, gl::Framebuffer *drawFramebuffer, const gl::Rectangle &drawRect,
+ bool blitRenderTarget, bool blitDepthStencil)
+{
+ endScene();
+
+ if (blitRenderTarget)
+ {
+ gl::Renderbuffer *readBuffer = readFramebuffer->getColorbuffer(0);
+ gl::Renderbuffer *drawBuffer = drawFramebuffer->getColorbuffer(0);
+ RenderTarget9 *readRenderTarget = NULL;
+ RenderTarget9 *drawRenderTarget = NULL;
+ IDirect3DSurface9* readSurface = NULL;
+ IDirect3DSurface9* drawSurface = NULL;
+
+ if (readBuffer)
+ {
+ readRenderTarget = RenderTarget9::makeRenderTarget9(readBuffer->getRenderTarget());
+ }
+ if (drawBuffer)
+ {
+ drawRenderTarget = RenderTarget9::makeRenderTarget9(drawBuffer->getRenderTarget());
+ }
+
+ if (readRenderTarget)
+ {
+ readSurface = readRenderTarget->getSurface();
+ }
+ if (drawRenderTarget)
+ {
+ drawSurface = drawRenderTarget->getSurface();
+ }
+
+ if (!readSurface || !drawSurface)
+ {
+ ERR("Failed to retrieve the render target.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ RECT srcRect;
+ srcRect.left = readRect.x;
+ srcRect.right = readRect.x + readRect.width;
+ srcRect.top = readRect.y;
+ srcRect.bottom = readRect.y + readRect.height;
+
+ RECT dstRect;
+ dstRect.left = drawRect.x;
+ dstRect.right = drawRect.x + drawRect.width;
+ dstRect.top = drawRect.y;
+ dstRect.bottom = drawRect.y + drawRect.height;
+
+ HRESULT result = mDevice->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE);
+
+ readSurface->Release();
+ drawSurface->Release();
+
+ if (FAILED(result))
+ {
+ ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result);
+ return false;
+ }
+ }
+
+ if (blitDepthStencil)
+ {
+ gl::Renderbuffer *readBuffer = readFramebuffer->getDepthOrStencilbuffer();
+ gl::Renderbuffer *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer();
+ RenderTarget9 *readDepthStencil = NULL;
+ RenderTarget9 *drawDepthStencil = NULL;
+ IDirect3DSurface9* readSurface = NULL;
+ IDirect3DSurface9* drawSurface = NULL;
+
+ if (readBuffer)
+ {
+ readDepthStencil = RenderTarget9::makeRenderTarget9(readBuffer->getDepthStencil());
+ }
+ if (drawBuffer)
+ {
+ drawDepthStencil = RenderTarget9::makeRenderTarget9(drawBuffer->getDepthStencil());
+ }
+
+ if (readDepthStencil)
+ {
+ readSurface = readDepthStencil->getSurface();
+ }
+ if (drawDepthStencil)
+ {
+ drawSurface = drawDepthStencil->getSurface();
+ }
+
+ if (!readSurface || !drawSurface)
+ {
+ ERR("Failed to retrieve the render target.");
+ return gl::error(GL_OUT_OF_MEMORY, false);
+ }
+
+ HRESULT result = mDevice->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE);
+
+ readSurface->Release();
+ drawSurface->Release();
+
+ if (FAILED(result))
+ {
+ ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels)
+{
+ RenderTarget9 *renderTarget = NULL;
+ IDirect3DSurface9 *surface = NULL;
+ gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer(0);
+
+ if (colorbuffer)
+ {
+ renderTarget = RenderTarget9::makeRenderTarget9(colorbuffer->getRenderTarget());
+ }
+
+ if (renderTarget)
+ {
+ surface = renderTarget->getSurface();
+ }
+
+ if (!surface)
+ {
+ // context must be lost
+ return;
+ }
+
+ D3DSURFACE_DESC desc;
+ surface->GetDesc(&desc);
+
+ if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
+ {
+ UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target
+ surface->Release();
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+
+ HRESULT result;
+ IDirect3DSurface9 *systemSurface = NULL;
+ bool directToPixels = !packReverseRowOrder && packAlignment <= 4 && getShareHandleSupport() &&
+ x == 0 && y == 0 && UINT(width) == desc.Width && UINT(height) == desc.Height &&
+ desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
+ if (directToPixels)
+ {
+ // Use the pixels ptr as a shared handle to write directly into client's memory
+ result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
+ D3DPOOL_SYSTEMMEM, &systemSurface, &pixels);
+ if (FAILED(result))
+ {
+ // Try again without the shared handle
+ directToPixels = false;
+ }
+ }
+
+ if (!directToPixels)
+ {
+ result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
+ D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ surface->Release();
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ result = mDevice->GetRenderTargetData(surface, systemSurface);
+ surface->Release();
+ surface = NULL;
+
+ if (FAILED(result))
+ {
+ systemSurface->Release();
+
+ // It turns out that D3D will sometimes produce more error
+ // codes than those documented.
+ if (d3d9::isDeviceLostError(result))
+ {
+ notifyDeviceLost();
+ return gl::error(GL_OUT_OF_MEMORY);
+ }
+ else
+ {
+ UNREACHABLE();
+ return;
+ }
+
+ }
+
+ if (directToPixels)
+ {
+ systemSurface->Release();
+ return;
+ }
+
+ RECT rect;
+ rect.left = gl::clamp(x, 0L, static_cast<LONG>(desc.Width));
+ rect.top = gl::clamp(y, 0L, static_cast<LONG>(desc.Height));
+ rect.right = gl::clamp(x + width, 0L, static_cast<LONG>(desc.Width));
+ rect.bottom = gl::clamp(y + height, 0L, static_cast<LONG>(desc.Height));
+
+ D3DLOCKED_RECT lock;
+ result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
+
+ if (FAILED(result))
+ {
+ UNREACHABLE();
+ systemSurface->Release();
+
+ return; // No sensible error to generate
+ }
+
+ unsigned char *dest = (unsigned char*)pixels;
+ unsigned short *dest16 = (unsigned short*)pixels;
+
+ unsigned char *source;
+ int inputPitch;
+ if (packReverseRowOrder)
+ {
+ source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1);
+ inputPitch = -lock.Pitch;
+ }
+ else
+ {
+ source = (unsigned char*)lock.pBits;
+ inputPitch = lock.Pitch;
+ }
+
+ unsigned int fastPixelSize = 0;
+
+ if (desc.Format == D3DFMT_A8R8G8B8 &&
+ format == GL_BGRA_EXT &&
+ type == GL_UNSIGNED_BYTE)
+ {
+ fastPixelSize = 4;
+ }
+ else if ((desc.Format == D3DFMT_A4R4G4B4 &&
+ format == GL_BGRA_EXT &&
+ type == GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT) ||
+ (desc.Format == D3DFMT_A1R5G5B5 &&
+ format == GL_BGRA_EXT &&
+ type == GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT))
+ {
+ fastPixelSize = 2;
+ }
+ else if (desc.Format == D3DFMT_A16B16G16R16F &&
+ format == GL_RGBA &&
+ type == GL_HALF_FLOAT_OES)
+ {
+ fastPixelSize = 8;
+ }
+ else if (desc.Format == D3DFMT_A32B32G32R32F &&
+ format == GL_RGBA &&
+ type == GL_FLOAT)
+ {
+ fastPixelSize = 16;
+ }
+
+ for (int j = 0; j < rect.bottom - rect.top; j++)
+ {
+ if (fastPixelSize != 0)
+ {
+ // Fast path for formats which require no translation:
+ // D3DFMT_A8R8G8B8 to BGRA/UNSIGNED_BYTE
+ // D3DFMT_A4R4G4B4 to BGRA/UNSIGNED_SHORT_4_4_4_4_REV_EXT
+ // D3DFMT_A1R5G5B5 to BGRA/UNSIGNED_SHORT_1_5_5_5_REV_EXT
+ // D3DFMT_A16B16G16R16F to RGBA/HALF_FLOAT_OES
+ // D3DFMT_A32B32G32R32F to RGBA/FLOAT
+ //
+ // Note that buffers with no alpha go through the slow path below.
+ memcpy(dest + j * outputPitch,
+ source + j * inputPitch,
+ (rect.right - rect.left) * fastPixelSize);
+ continue;
+ }
+ else if (desc.Format == D3DFMT_A8R8G8B8 &&
+ format == GL_RGBA &&
+ type == GL_UNSIGNED_BYTE)
+ {
+ // Fast path for swapping red with blue
+ for (int i = 0; i < rect.right - rect.left; i++)
+ {
+ unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
+ *(unsigned int*)(dest + 4 * i + j * outputPitch) =
+ (argb & 0xFF00FF00) | // Keep alpha and green
+ (argb & 0x00FF0000) >> 16 | // Move red to blue
+ (argb & 0x000000FF) << 16; // Move blue to red
+ }
+ continue;
+ }
+
+ for (int i = 0; i < rect.right - rect.left; i++)
+ {
+ float r;
+ float g;
+ float b;
+ float a;
+
+ switch (desc.Format)
+ {
+ case D3DFMT_R5G6B5:
+ {
+ unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch);
+
+ a = 1.0f;
+ b = (rgb & 0x001F) * (1.0f / 0x001F);
+ g = (rgb & 0x07E0) * (1.0f / 0x07E0);
+ r = (rgb & 0xF800) * (1.0f / 0xF800);
+ }
+ break;
+ case D3DFMT_A1R5G5B5:
+ {
+ unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch);
+
+ a = (argb & 0x8000) ? 1.0f : 0.0f;
+ b = (argb & 0x001F) * (1.0f / 0x001F);
+ g = (argb & 0x03E0) * (1.0f / 0x03E0);
+ r = (argb & 0x7C00) * (1.0f / 0x7C00);
+ }
+ break;
+ case D3DFMT_A8R8G8B8:
+ {
+ unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
+
+ a = (argb & 0xFF000000) * (1.0f / 0xFF000000);
+ b = (argb & 0x000000FF) * (1.0f / 0x000000FF);
+ g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00);
+ r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000);
+ }
+ break;
+ case D3DFMT_X8R8G8B8:
+ {
+ unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch);
+
+ a = 1.0f;
+ b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF);
+ g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00);
+ r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000);
+ }
+ break;
+ case D3DFMT_A2R10G10B10:
+ {
+ unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
+
+ a = (argb & 0xC0000000) * (1.0f / 0xC0000000);
+ b = (argb & 0x000003FF) * (1.0f / 0x000003FF);
+ g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00);
+ r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000);
+ }
+ break;
+ case D3DFMT_A32B32G32R32F:
+ {
+ // float formats in D3D are stored rgba, rather than the other way round
+ r = *((float*)(source + 16 * i + j * inputPitch) + 0);
+ g = *((float*)(source + 16 * i + j * inputPitch) + 1);
+ b = *((float*)(source + 16 * i + j * inputPitch) + 2);
+ a = *((float*)(source + 16 * i + j * inputPitch) + 3);
+ }
+ break;
+ case D3DFMT_A16B16G16R16F:
+ {
+ // float formats in D3D are stored rgba, rather than the other way round
+ r = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 0));
+ g = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 1));
+ b = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 2));
+ a = gl::float16ToFloat32(*((unsigned short*)(source + 8 * i + j * inputPitch) + 3));
+ }
+ break;
+ default:
+ UNIMPLEMENTED(); // FIXME
+ UNREACHABLE();
+ return;
+ }
+
+ switch (format)
+ {
+ case GL_RGBA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f);
+ dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);
+ dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f);
+ dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_BGRA_EXT:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * b + 0.5f);
+ dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);
+ dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * r + 0.5f);
+ dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f);
+ break;
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
+ // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
+ // this type is packed as follows:
+ // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ // --------------------------------------------------------------------------------
+ // | 4th | 3rd | 2nd | 1st component |
+ // --------------------------------------------------------------------------------
+ // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
+ dest16[i + j * outputPitch / sizeof(unsigned short)] =
+ ((unsigned short)(15 * a + 0.5f) << 12)|
+ ((unsigned short)(15 * r + 0.5f) << 8) |
+ ((unsigned short)(15 * g + 0.5f) << 4) |
+ ((unsigned short)(15 * b + 0.5f) << 0);
+ break;
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
+ // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
+ // this type is packed as follows:
+ // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ // --------------------------------------------------------------------------------
+ // | 4th | 3rd | 2nd | 1st component |
+ // --------------------------------------------------------------------------------
+ // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
+ dest16[i + j * outputPitch / sizeof(unsigned short)] =
+ ((unsigned short)( a + 0.5f) << 15) |
+ ((unsigned short)(31 * r + 0.5f) << 10) |
+ ((unsigned short)(31 * g + 0.5f) << 5) |
+ ((unsigned short)(31 * b + 0.5f) << 0);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_RGB:
+ switch (type)
+ {
+ case GL_UNSIGNED_SHORT_5_6_5:
+ dest16[i + j * outputPitch / sizeof(unsigned short)] =
+ ((unsigned short)(31 * b + 0.5f) << 0) |
+ ((unsigned short)(63 * g + 0.5f) << 5) |
+ ((unsigned short)(31 * r + 0.5f) << 11);
+ break;
+ case GL_UNSIGNED_BYTE:
+ dest[3 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f);
+ dest[3 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);
+ dest[3 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+
+ systemSurface->UnlockRect();
+
+ systemSurface->Release();
+}
+
+RenderTarget *Renderer9::createRenderTarget(SwapChain *swapChain, bool depth)
+{
+ SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain);
+ IDirect3DSurface9 *surface = NULL;
+ if (depth)
+ {
+ surface = swapChain9->getDepthStencil();
+ }
+ else
+ {
+ surface = swapChain9->getRenderTarget();
+ }
+
+ RenderTarget9 *renderTarget = new RenderTarget9(this, surface);
+
+ return renderTarget;
+}
+
+RenderTarget *Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth)
+{
+ RenderTarget9 *renderTarget = new RenderTarget9(this, width, height, format, samples);
+ return renderTarget;
+}
+
+ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type)
+{
+ ShaderExecutable9 *executable = NULL;
+
+ switch (type)
+ {
+ case rx::SHADER_VERTEX:
+ {
+ IDirect3DVertexShader9 *vshader = createVertexShader((DWORD*)function, length);
+ if (vshader)
+ {
+ executable = new ShaderExecutable9(function, length, vshader);
+ }
+ }
+ break;
+ case rx::SHADER_PIXEL:
+ {
+ IDirect3DPixelShader9 *pshader = createPixelShader((DWORD*)function, length);
+ if (pshader)
+ {
+ executable = new ShaderExecutable9(function, length, pshader);
+ }
+ }
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ return executable;
+}
+
+ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type)
+{
+ const char *profile = NULL;
+
+ switch (type)
+ {
+ case rx::SHADER_VERTEX:
+ profile = getMajorShaderModel() >= 3 ? "vs_3_0" : "vs_2_0";
+ break;
+ case rx::SHADER_PIXEL:
+ profile = getMajorShaderModel() >= 3 ? "ps_3_0" : "ps_2_0";
+ break;
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+
+ ID3DBlob *binary = (ID3DBlob*)compileToBinary(infoLog, shaderHLSL, profile, ANGLE_COMPILE_OPTIMIZATION_LEVEL, true);
+ if (!binary)
+ return NULL;
+
+ ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type);
+ binary->Release();
+
+ return executable;
+}
+
+bool Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
+{
+ return mBlit->boxFilter(source, dest);
+}
+
+D3DPOOL Renderer9::getTexturePool(DWORD usage) const
+{
+ if (mD3d9Ex != NULL)
+ {
+ return D3DPOOL_DEFAULT;
+ }
+ else
+ {
+ if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET)))
+ {
+ return D3DPOOL_MANAGED;
+ }
+ }
+
+ return D3DPOOL_DEFAULT;
+}
+
+bool Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged)
+{
+ if (source && dest)
+ {
+ HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
+
+ if (fromManaged)
+ {
+ D3DSURFACE_DESC desc;
+ source->GetDesc(&desc);
+
+ IDirect3DSurface9 *surf = 0;
+ result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL);
+
+ if (SUCCEEDED(result))
+ {
+ Image9::copyLockableSurfaces(surf, source);
+ result = mDevice->UpdateSurface(surf, NULL, dest, NULL);
+ surf->Release();
+ }
+ }
+ else
+ {
+ endScene();
+ result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
+ }
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+Image *Renderer9::createImage()
+{
+ return new Image9();
+}
+
+void Renderer9::generateMipmap(Image *dest, Image *src)
+{
+ Image9 *src9 = Image9::makeImage9(src);
+ Image9 *dst9 = Image9::makeImage9(dest);
+ Image9::generateMipmap(dst9, src9);
+}
+
+TextureStorage *Renderer9::createTextureStorage2D(SwapChain *swapChain)
+{
+ SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain);
+ return new TextureStorage9_2D(this, swapChain9);
+}
+
+TextureStorage *Renderer9::createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
+{
+ return new TextureStorage9_2D(this, levels, internalformat, usage, forceRenderable, width, height);
+}
+
+TextureStorage *Renderer9::createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
+{
+ return new TextureStorage9_Cube(this, levels, internalformat, usage, forceRenderable, size);
+}
+
+bool Renderer9::getLUID(LUID *adapterLuid) const
+{
+ adapterLuid->HighPart = 0;
+ adapterLuid->LowPart = 0;
+
+ if (mD3d9Ex)
+ {
+ mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid);
+ return true;
+ }
+
+ return false;
+}
+
+}
diff --git a/src/libGLESv2/renderer/Renderer9.h b/src/libGLESv2/renderer/Renderer9.h
new file mode 100644
index 00000000..2873e611
--- /dev/null
+++ b/src/libGLESv2/renderer/Renderer9.h
@@ -0,0 +1,349 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderer9.h: Defines a back-end specific class for the D3D9 renderer.
+
+#ifndef LIBGLESV2_RENDERER_RENDERER9_H_
+#define LIBGLESV2_RENDERER_RENDERER9_H_
+
+#include "common/angleutils.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/renderer/ShaderCache.h"
+#include "libGLESv2/renderer/VertexDeclarationCache.h"
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/renderer/RenderTarget.h"
+
+namespace gl
+{
+class Renderbuffer;
+}
+
+namespace rx
+{
+class VertexDataManager;
+class IndexDataManager;
+class StreamingIndexBufferInterface;
+struct TranslatedAttribute;
+
+class Renderer9 : public Renderer
+{
+ public:
+ Renderer9(egl::Display *display, HDC hDc, bool softwareDevice);
+ virtual ~Renderer9();
+
+ static Renderer9 *makeRenderer9(Renderer *renderer);
+
+ virtual EGLint initialize();
+ virtual bool resetDevice();
+
+ virtual int generateConfigs(ConfigDesc **configDescList);
+ virtual void deleteConfigs(ConfigDesc *configDescList);
+
+ void startScene();
+ void endScene();
+
+ virtual void sync(bool block);
+
+ virtual SwapChain *createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat);
+
+ IDirect3DQuery9* allocateEventQuery();
+ void freeEventQuery(IDirect3DQuery9* query);
+
+ // resource creation
+ IDirect3DVertexShader9 *createVertexShader(const DWORD *function, size_t length);
+ IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length);
+ HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer);
+ HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer);
+#if 0
+ void *createTexture2D();
+ void *createTextureCube();
+ void *createQuery();
+ void *createIndexBuffer();
+ void *createVertexbuffer();
+
+ // state setup
+ void applyShaders();
+ void applyConstants();
+#endif
+ virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler);
+ virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture);
+
+ virtual void setRasterizerState(const gl::RasterizerState &rasterState);
+ virtual void setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor,
+ unsigned int sampleMask);
+ virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef,
+ int stencilBackRef, bool frontFaceCCW);
+
+ virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled);
+ virtual bool setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
+ bool ignoreViewport);
+
+ virtual bool applyRenderTarget(gl::Framebuffer *frameBuffer);
+ virtual void applyShaders(gl::ProgramBinary *programBinary);
+ virtual void applyUniforms(gl::ProgramBinary *programBinary, gl::UniformArray *uniformArray);
+ virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount);
+ virtual GLenum applyVertexBuffer(gl::ProgramBinary *programBinary, gl::VertexAttribute vertexAttributes[], GLint first, GLsizei count, GLsizei instances);
+ virtual GLenum applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
+
+ virtual void drawArrays(GLenum mode, GLsizei count, GLsizei instances);
+ virtual void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
+
+ virtual void clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer);
+
+ virtual void markAllStateDirty();
+
+ // lost device
+ void notifyDeviceLost();
+ virtual bool isDeviceLost();
+ virtual bool testDeviceLost(bool notify);
+ virtual bool testDeviceResettable();
+
+ // Renderer capabilities
+ IDirect3DDevice9 *getDevice() { return mDevice; }
+ virtual DWORD getAdapterVendor() const;
+ virtual std::string getRendererDescription() const;
+ virtual GUID getAdapterIdentifier() const;
+
+ virtual bool getBGRATextureSupport() const;
+ virtual bool getDXT1TextureSupport();
+ virtual bool getDXT3TextureSupport();
+ virtual bool getDXT5TextureSupport();
+ virtual bool getEventQuerySupport();
+ virtual bool getFloat32TextureSupport(bool *filtering, bool *renderable);
+ virtual bool getFloat16TextureSupport(bool *filtering, bool *renderable);
+ virtual bool getLuminanceTextureSupport();
+ virtual bool getLuminanceAlphaTextureSupport();
+ virtual unsigned int getMaxVertexTextureImageUnits() const;
+ virtual unsigned int getMaxCombinedTextureImageUnits() const;
+ virtual unsigned int getReservedVertexUniformVectors() const;
+ virtual unsigned int getReservedFragmentUniformVectors() const;
+ virtual unsigned int getMaxVertexUniformVectors() const;
+ virtual unsigned int getMaxFragmentUniformVectors() const;
+ virtual unsigned int getMaxVaryingVectors() const;
+ virtual bool getNonPower2TextureSupport() const;
+ virtual bool getDepthTextureSupport() const;
+ virtual bool getOcclusionQuerySupport() const;
+ virtual bool getInstancingSupport() const;
+ virtual bool getTextureFilterAnisotropySupport() const;
+ virtual float getTextureMaxAnisotropy() const;
+ virtual bool getShareHandleSupport() const;
+ virtual bool getDerivativeInstructionSupport() const;
+ virtual bool getPostSubBufferSupport() const;
+
+ virtual int getMajorShaderModel() const;
+ virtual float getMaxPointSize() const;
+ virtual int getMaxViewportDimension() const;
+ virtual int getMaxTextureWidth() const;
+ virtual int getMaxTextureHeight() const;
+ virtual bool get32BitIndexSupport() const;
+ DWORD getCapsDeclTypes() const;
+ virtual int getMinSwapInterval() const;
+ virtual int getMaxSwapInterval() const;
+
+ virtual GLsizei getMaxSupportedSamples() const;
+ int getNearestSupportedSamples(D3DFORMAT format, int requested) const;
+
+ virtual unsigned int getMaxRenderTargets() const;
+
+ D3DFORMAT ConvertTextureInternalFormat(GLint internalformat);
+
+ // Pixel operations
+ virtual bool copyToRenderTarget(TextureStorageInterface2D *dest, TextureStorageInterface2D *source);
+ virtual bool copyToRenderTarget(TextureStorageInterfaceCube *dest, TextureStorageInterfaceCube *source);
+
+ virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterface2D *storage, GLint level);
+ virtual bool copyImage(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat,
+ GLint xoffset, GLint yoffset, TextureStorageInterfaceCube *storage, GLenum target, GLint level);
+
+ virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect,
+ bool blitRenderTarget, bool blitDepthStencil);
+ virtual void readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLsizei outputPitch, bool packReverseRowOrder, GLint packAlignment, void* pixels);
+
+ // RenderTarget creation
+ virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth);
+ virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples, bool depth);
+
+ // Shader operations
+ virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type);
+ virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type);
+
+ // Image operations
+ virtual Image *createImage();
+ virtual void generateMipmap(Image *dest, Image *source);
+ virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain);
+ virtual TextureStorage *createTextureStorage2D(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height);
+ virtual TextureStorage *createTextureStorageCube(int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size);
+
+ // Buffer creation
+ virtual VertexBuffer *createVertexBuffer();
+ virtual IndexBuffer *createIndexBuffer();
+ virtual BufferStorage *createBufferStorage();
+
+ // Query and Fence creation
+ virtual QueryImpl *createQuery(GLenum type);
+ virtual FenceImpl *createFence();
+
+ // D3D9-renderer specific methods
+ bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest);
+
+ D3DPOOL getTexturePool(DWORD usage) const;
+
+ virtual bool getLUID(LUID *adapterLuid) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Renderer9);
+
+ void applyUniformnfv(gl::Uniform *targetUniform, const GLfloat *v);
+ void applyUniformniv(gl::Uniform *targetUniform, const GLint *v);
+ void applyUniformnbv(gl::Uniform *targetUniform, const GLint *v);
+
+ void drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
+ void drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer);
+
+ void getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray);
+ bool copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged);
+ gl::Renderbuffer *getNullColorbuffer(gl::Renderbuffer *depthbuffer);
+
+ D3DPOOL getBufferPool(DWORD usage) const;
+
+ HMODULE mD3d9Module;
+ HDC mDc;
+
+ void initializeDevice();
+ D3DPRESENT_PARAMETERS getDefaultPresentParameters();
+ void releaseDeviceResources();
+
+ UINT mAdapter;
+ D3DDEVTYPE mDeviceType;
+ bool mSoftwareDevice; // FIXME: Deprecate
+ 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.
+
+ Blit *mBlit;
+
+ HWND mDeviceWindow;
+
+ bool mDeviceLost;
+ D3DCAPS9 mDeviceCaps;
+ D3DADAPTER_IDENTIFIER9 mAdapterIdentifier;
+
+ D3DPRIMITIVETYPE mPrimitiveType;
+ int mPrimitiveCount;
+ GLsizei mRepeatDraw;
+
+ bool mSceneStarted;
+ bool mSupportsNonPower2Textures;
+ bool mSupportsTextureFilterAnisotropy;
+ int mMinSwapInterval;
+ int mMaxSwapInterval;
+
+ bool mOcclusionQuerySupport;
+ bool mEventQuerySupport;
+ bool mVertexTextureSupport;
+
+ bool mDepthTextureSupport;
+
+ bool mFloat32TextureSupport;
+ bool mFloat32FilterSupport;
+ bool mFloat32RenderSupport;
+
+ bool mFloat16TextureSupport;
+ bool mFloat16FilterSupport;
+ bool mFloat16RenderSupport;
+
+ bool mDXT1TextureSupport;
+ bool mDXT3TextureSupport;
+ bool mDXT5TextureSupport;
+
+ bool mLuminanceTextureSupport;
+ bool mLuminanceAlphaTextureSupport;
+
+ std::map<D3DFORMAT, bool *> mMultiSampleSupport;
+ GLsizei mMaxSupportedSamples;
+
+ // current render target states
+ unsigned int mAppliedRenderTargetSerial;
+ unsigned int mAppliedDepthbufferSerial;
+ unsigned int mAppliedStencilbufferSerial;
+ bool mDepthStencilInitialized;
+ bool mRenderTargetDescInitialized;
+ rx::RenderTarget::Desc mRenderTargetDesc;
+ unsigned int mCurStencilSize;
+ unsigned int mCurDepthSize;
+
+ IDirect3DStateBlock9 *mMaskedClearSavedState;
+
+ // previously set render states
+ bool mForceSetDepthStencilState;
+ gl::DepthStencilState mCurDepthStencilState;
+ int mCurStencilRef;
+ int mCurStencilBackRef;
+ bool mCurFrontFaceCCW;
+
+ bool mForceSetRasterState;
+ gl::RasterizerState mCurRasterState;
+
+ bool mForceSetScissor;
+ gl::Rectangle mCurScissor;
+ bool mScissorEnabled;
+
+ bool mForceSetViewport;
+ gl::Rectangle mCurViewport;
+ float mCurNear;
+ float mCurFar;
+
+ bool mForceSetBlendState;
+ gl::BlendState mCurBlendState;
+ gl::Color mCurBlendColor;
+ GLuint mCurSampleMask;
+
+ // Currently applied sampler states
+ bool mForceSetVertexSamplerStates[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
+ gl::SamplerState mCurVertexSamplerStates[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
+
+ bool mForceSetPixelSamplerStates[gl::MAX_TEXTURE_IMAGE_UNITS];
+ gl::SamplerState mCurPixelSamplerStates[gl::MAX_TEXTURE_IMAGE_UNITS];
+
+ // Currently applied textures
+ unsigned int mCurVertexTextureSerials[gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS];
+ unsigned int mCurPixelTextureSerials[gl::MAX_TEXTURE_IMAGE_UNITS];
+
+ unsigned int mAppliedIBSerial;
+ unsigned int mAppliedProgramBinarySerial;
+
+ rx::dx_VertexConstants mVertexConstants;
+ rx::dx_PixelConstants mPixelConstants;
+ bool mDxUniformsDirty;
+
+ // A pool of event queries that are currently unused.
+ std::vector<IDirect3DQuery9*> mEventQueryPool;
+ VertexShaderCache mVertexShaderCache;
+ PixelShaderCache mPixelShaderCache;
+
+ VertexDataManager *mVertexDataManager;
+ VertexDeclarationCache mVertexDeclarationCache;
+
+ IndexDataManager *mIndexDataManager;
+ StreamingIndexBufferInterface *mLineLoopIB;
+
+ enum { NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 };
+ struct NullColorbufferCacheEntry
+ {
+ UINT lruCount;
+ int width;
+ int height;
+ gl::Renderbuffer *buffer;
+ } mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES];
+ UINT mMaxNullColorbufferLRU;
+
+};
+
+}
+#endif // LIBGLESV2_RENDERER_RENDERER9_H_
diff --git a/src/libGLESv2/renderer/ShaderCache.h b/src/libGLESv2/renderer/ShaderCache.h
new file mode 100644
index 00000000..4391ac27
--- /dev/null
+++ b/src/libGLESv2/renderer/ShaderCache.h
@@ -0,0 +1,110 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ShaderCache: Defines rx::ShaderCache, a cache of Direct3D shader objects
+// keyed by their byte code.
+
+#ifndef LIBGLESV2_RENDERER_SHADER_CACHE_H_
+#define LIBGLESV2_RENDERER_SHADER_CACHE_H_
+
+#include "common/debug.h"
+
+namespace rx
+{
+template <typename ShaderObject>
+class ShaderCache
+{
+ public:
+ ShaderCache() : mDevice(NULL)
+ {
+ }
+
+ ~ShaderCache()
+ {
+ // Call clear while the device is still valid.
+ ASSERT(mMap.empty());
+ }
+
+ void initialize(IDirect3DDevice9* device)
+ {
+ mDevice = device;
+ }
+
+ ShaderObject *create(const DWORD *function, size_t length)
+ {
+ std::string key(reinterpret_cast<const char*>(function), length);
+ typename Map::iterator it = mMap.find(key);
+ if (it != mMap.end())
+ {
+ it->second->AddRef();
+ return it->second;
+ }
+
+ ShaderObject *shader;
+ HRESULT result = createShader(function, &shader);
+ if (FAILED(result))
+ {
+ return NULL;
+ }
+
+ // Random eviction policy.
+ if (mMap.size() >= kMaxMapSize)
+ {
+ mMap.begin()->second->Release();
+ mMap.erase(mMap.begin());
+ }
+
+ shader->AddRef();
+ mMap[key] = shader;
+
+ return shader;
+ }
+
+ void clear()
+ {
+ for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it)
+ {
+ it->second->Release();
+ }
+
+ mMap.clear();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShaderCache);
+
+ const static size_t kMaxMapSize = 100;
+
+ HRESULT createShader(const DWORD *function, IDirect3DVertexShader9 **shader)
+ {
+ return mDevice->CreateVertexShader(function, shader);
+ }
+
+ HRESULT createShader(const DWORD *function, IDirect3DPixelShader9 **shader)
+ {
+ return mDevice->CreatePixelShader(function, shader);
+ }
+
+#ifndef HASH_MAP
+# ifdef _MSC_VER
+# define HASH_MAP stdext::hash_map
+# else
+# define HASH_MAP std::unordered_map
+# endif
+#endif
+
+ typedef HASH_MAP<std::string, ShaderObject*> Map;
+ Map mMap;
+
+ IDirect3DDevice9 *mDevice;
+};
+
+typedef ShaderCache<IDirect3DVertexShader9> VertexShaderCache;
+typedef ShaderCache<IDirect3DPixelShader9> PixelShaderCache;
+
+}
+
+#endif // LIBGLESV2_RENDERER_SHADER_CACHE_H_
diff --git a/src/libGLESv2/renderer/ShaderExecutable.h b/src/libGLESv2/renderer/ShaderExecutable.h
new file mode 100644
index 00000000..293e3408
--- /dev/null
+++ b/src/libGLESv2/renderer/ShaderExecutable.h
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ShaderExecutable.h: Defines a renderer-agnostic class to contain shader
+// executable implementation details.
+
+#ifndef LIBGLESV2_RENDERER_SHADEREXECUTABLE_H_
+#define LIBGLESV2_RENDERER_SHADEREXECUTABLE_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+
+class ShaderExecutable
+{
+ public:
+ ShaderExecutable(const void *function, size_t length) : mLength(length)
+ {
+ mFunction = new char[length];
+ memcpy(mFunction, function, length);
+ }
+
+ virtual ~ShaderExecutable()
+ {
+ delete[] mFunction;
+ }
+
+ void *getFunction() const
+ {
+ return mFunction;
+ }
+
+ size_t getLength() const
+ {
+ return mLength;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShaderExecutable);
+
+ void *mFunction;
+ const size_t mLength;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_
diff --git a/src/libGLESv2/renderer/ShaderExecutable11.cpp b/src/libGLESv2/renderer/ShaderExecutable11.cpp
new file mode 100644
index 00000000..e1eb5603
--- /dev/null
+++ b/src/libGLESv2/renderer/ShaderExecutable11.cpp
@@ -0,0 +1,109 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ShaderExecutable11.cpp: Implements a D3D11-specific class to contain shader
+// executable implementation details.
+
+#include "libGLESv2/renderer/ShaderExecutable11.h"
+
+#include "common/debug.h"
+
+namespace rx
+{
+
+ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable)
+ : ShaderExecutable(function, length)
+{
+ mPixelExecutable = executable;
+ mVertexExecutable = NULL;
+ mGeometryExecutable = NULL;
+
+ mConstantBuffer = NULL;
+}
+
+ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable)
+ : ShaderExecutable(function, length)
+{
+ mVertexExecutable = executable;
+ mPixelExecutable = NULL;
+ mGeometryExecutable = NULL;
+
+ mConstantBuffer = NULL;
+}
+
+ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable)
+ : ShaderExecutable(function, length)
+{
+ mGeometryExecutable = executable;
+ mVertexExecutable = NULL;
+ mPixelExecutable = NULL;
+
+ mConstantBuffer = NULL;
+}
+
+ShaderExecutable11::~ShaderExecutable11()
+{
+ if (mVertexExecutable)
+ {
+ mVertexExecutable->Release();
+ }
+ if (mPixelExecutable)
+ {
+ mPixelExecutable->Release();
+ }
+ if (mGeometryExecutable)
+ {
+ mGeometryExecutable->Release();
+ }
+
+ if (mConstantBuffer)
+ {
+ mConstantBuffer->Release();
+ }
+}
+
+ShaderExecutable11 *ShaderExecutable11::makeShaderExecutable11(ShaderExecutable *executable)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable11*, executable));
+ return static_cast<ShaderExecutable11*>(executable);
+}
+
+ID3D11VertexShader *ShaderExecutable11::getVertexShader() const
+{
+ return mVertexExecutable;
+}
+
+ID3D11PixelShader *ShaderExecutable11::getPixelShader() const
+{
+ return mPixelExecutable;
+}
+
+ID3D11GeometryShader *ShaderExecutable11::getGeometryShader() const
+{
+ return mGeometryExecutable;
+}
+
+ID3D11Buffer *ShaderExecutable11::getConstantBuffer(ID3D11Device *device, unsigned int registerCount)
+{
+ if (!mConstantBuffer && registerCount > 0)
+ {
+ D3D11_BUFFER_DESC constantBufferDescription = {0};
+ constantBufferDescription.ByteWidth = registerCount * sizeof(float[4]);
+ 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 = device->CreateBuffer(&constantBufferDescription, NULL, &mConstantBuffer);
+ ASSERT(SUCCEEDED(result));
+ }
+
+ return mConstantBuffer;
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/ShaderExecutable11.h b/src/libGLESv2/renderer/ShaderExecutable11.h
new file mode 100644
index 00000000..c6ec1cf7
--- /dev/null
+++ b/src/libGLESv2/renderer/ShaderExecutable11.h
@@ -0,0 +1,47 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ShaderExecutable11.h: Defines a D3D11-specific class to contain shader
+// executable implementation details.
+
+#ifndef LIBGLESV2_RENDERER_SHADEREXECUTABLE11_H_
+#define LIBGLESV2_RENDERER_SHADEREXECUTABLE11_H_
+
+#include "libGLESv2/renderer/ShaderExecutable.h"
+
+namespace rx
+{
+
+class ShaderExecutable11 : public ShaderExecutable
+{
+ public:
+ ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable);
+ ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable);
+ ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable);
+
+ virtual ~ShaderExecutable11();
+
+ static ShaderExecutable11 *makeShaderExecutable11(ShaderExecutable *executable);
+
+ ID3D11PixelShader *getPixelShader() const;
+ ID3D11VertexShader *getVertexShader() const;
+ ID3D11GeometryShader *getGeometryShader() const;
+
+ ID3D11Buffer *getConstantBuffer(ID3D11Device *device, unsigned int registerCount);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShaderExecutable11);
+
+ ID3D11PixelShader *mPixelExecutable;
+ ID3D11VertexShader *mVertexExecutable;
+ ID3D11GeometryShader *mGeometryExecutable;
+
+ ID3D11Buffer *mConstantBuffer;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE11_H_
diff --git a/src/libGLESv2/renderer/ShaderExecutable9.cpp b/src/libGLESv2/renderer/ShaderExecutable9.cpp
new file mode 100644
index 00000000..98868a3f
--- /dev/null
+++ b/src/libGLESv2/renderer/ShaderExecutable9.cpp
@@ -0,0 +1,60 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ShaderExecutable9.cpp: Implements a D3D9-specific class to contain shader
+// executable implementation details.
+
+#include "libGLESv2/renderer/ShaderExecutable9.h"
+
+#include "common/debug.h"
+
+namespace rx
+{
+
+ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable)
+ : ShaderExecutable(function, length)
+{
+ mPixelExecutable = executable;
+ mVertexExecutable = NULL;
+}
+
+ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable)
+ : ShaderExecutable(function, length)
+{
+ mVertexExecutable = executable;
+ mPixelExecutable = NULL;
+}
+
+ShaderExecutable9::~ShaderExecutable9()
+{
+ if (mVertexExecutable)
+ {
+ mVertexExecutable->Release();
+ }
+ if (mPixelExecutable)
+ {
+ mPixelExecutable->Release();
+ }
+}
+
+ShaderExecutable9 *ShaderExecutable9::makeShaderExecutable9(ShaderExecutable *executable)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable9*, executable));
+ return static_cast<ShaderExecutable9*>(executable);
+}
+
+IDirect3DVertexShader9 *ShaderExecutable9::getVertexShader() const
+{
+ return mVertexExecutable;
+}
+
+IDirect3DPixelShader9 *ShaderExecutable9::getPixelShader() const
+{
+ return mPixelExecutable;
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/ShaderExecutable9.h b/src/libGLESv2/renderer/ShaderExecutable9.h
new file mode 100644
index 00000000..fa1e6c28
--- /dev/null
+++ b/src/libGLESv2/renderer/ShaderExecutable9.h
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ShaderExecutable9.h: Defines a D3D9-specific class to contain shader
+// executable implementation details.
+
+#ifndef LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_
+#define LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_
+
+#include "libGLESv2/renderer/ShaderExecutable.h"
+
+namespace rx
+{
+
+class ShaderExecutable9 : public ShaderExecutable
+{
+ public:
+ ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable);
+ ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable);
+ virtual ~ShaderExecutable9();
+
+ static ShaderExecutable9 *makeShaderExecutable9(ShaderExecutable *executable);
+
+ IDirect3DPixelShader9 *getPixelShader() const;
+ IDirect3DVertexShader9 *getVertexShader() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShaderExecutable9);
+
+ IDirect3DPixelShader9 *mPixelExecutable;
+ IDirect3DVertexShader9 *mVertexExecutable;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_ \ No newline at end of file
diff --git a/src/libGLESv2/renderer/SwapChain.h b/src/libGLESv2/renderer/SwapChain.h
new file mode 100644
index 00000000..14c0515f
--- /dev/null
+++ b/src/libGLESv2/renderer/SwapChain.h
@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// SwapChain.h: Defines a back-end specific class that hides the details of the
+// implementation-specific swapchain.
+
+#ifndef LIBGLESV2_RENDERER_SWAPCHAIN_H_
+#define LIBGLESV2_RENDERER_SWAPCHAIN_H_
+
+#include "common/angleutils.h"
+
+namespace rx
+{
+
+class SwapChain
+{
+ public:
+ SwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat)
+ : mWindow(window), mShareHandle(shareHandle), mBackBufferFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat)
+ {
+ }
+
+ virtual ~SwapChain() {};
+
+ virtual EGLint resize(EGLint backbufferWidth, EGLint backbufferSize) = 0;
+ virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval) = 0;
+ virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height) = 0;
+ virtual void recreate() = 0;
+
+ virtual HANDLE getShareHandle() {return mShareHandle;};
+
+ protected:
+ const HWND mWindow; // Window that the surface is created for.
+ const GLenum mBackBufferFormat;
+ const GLenum mDepthBufferFormat;
+
+ HANDLE mShareHandle;
+};
+
+}
+#endif // LIBGLESV2_RENDERER_SWAPCHAIN_H_
diff --git a/src/libGLESv2/renderer/SwapChain11.cpp b/src/libGLESv2/renderer/SwapChain11.cpp
new file mode 100644
index 00000000..87422be7
--- /dev/null
+++ b/src/libGLESv2/renderer/SwapChain11.cpp
@@ -0,0 +1,767 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain.
+
+#include "libGLESv2/renderer/SwapChain11.h"
+
+#include "libGLESv2/renderer/renderer11_utils.h"
+#include "libGLESv2/renderer/Renderer11.h"
+#include "libGLESv2/renderer/shaders/compiled/passthrough11vs.h"
+#include "libGLESv2/renderer/shaders/compiled/passthroughrgba11ps.h"
+
+namespace rx
+{
+
+SwapChain11::SwapChain11(Renderer11 *renderer, HWND window, HANDLE shareHandle,
+ GLenum backBufferFormat, GLenum depthBufferFormat)
+ : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat)
+{
+ mSwapChain = NULL;
+ mBackBufferTexture = NULL;
+ mBackBufferRTView = NULL;
+ mOffscreenTexture = NULL;
+ mOffscreenRTView = NULL;
+ mOffscreenSRView = NULL;
+ mDepthStencilTexture = NULL;
+ mDepthStencilDSView = NULL;
+ mQuadVB = NULL;
+ mPassThroughSampler = NULL;
+ mPassThroughIL = NULL;
+ mPassThroughVS = NULL;
+ mPassThroughPS = NULL;
+ mWidth = -1;
+ mHeight = -1;
+ mSwapInterval = 0;
+ mAppCreatedShareHandle = mShareHandle != NULL;
+ mPassThroughResourcesInit = false;
+}
+
+SwapChain11::~SwapChain11()
+{
+ release();
+}
+
+void SwapChain11::release()
+{
+ if (mSwapChain)
+ {
+ mSwapChain->Release();
+ mSwapChain = NULL;
+ }
+
+ if (mBackBufferTexture)
+ {
+ mBackBufferTexture->Release();
+ mBackBufferTexture = NULL;
+ }
+
+ if (mBackBufferRTView)
+ {
+ mBackBufferRTView->Release();
+ mBackBufferRTView = NULL;
+ }
+
+ if (mOffscreenTexture)
+ {
+ mOffscreenTexture->Release();
+ mOffscreenTexture = NULL;
+ }
+
+ if (mOffscreenRTView)
+ {
+ mOffscreenRTView->Release();
+ mOffscreenRTView = NULL;
+ }
+
+ if (mOffscreenSRView)
+ {
+ mOffscreenSRView->Release();
+ mOffscreenSRView = NULL;
+ }
+
+ if (mDepthStencilTexture)
+ {
+ mDepthStencilTexture->Release();
+ mDepthStencilTexture = NULL;
+ }
+
+ if (mDepthStencilDSView)
+ {
+ mDepthStencilDSView->Release();
+ mDepthStencilDSView = NULL;
+ }
+
+ if (mQuadVB)
+ {
+ mQuadVB->Release();
+ mQuadVB = NULL;
+ }
+
+ if (mPassThroughSampler)
+ {
+ mPassThroughSampler->Release();
+ mPassThroughSampler = NULL;
+ }
+
+ if (mPassThroughIL)
+ {
+ mPassThroughIL->Release();
+ mPassThroughIL = NULL;
+ }
+
+ if (mPassThroughVS)
+ {
+ mPassThroughVS->Release();
+ mPassThroughVS = NULL;
+ }
+
+ if (mPassThroughPS)
+ {
+ mPassThroughPS->Release();
+ mPassThroughPS = NULL;
+ }
+
+ if (!mAppCreatedShareHandle)
+ {
+ mShareHandle = NULL;
+ }
+}
+
+void SwapChain11::releaseOffscreenTexture()
+{
+ if (mOffscreenTexture)
+ {
+ mOffscreenTexture->Release();
+ mOffscreenTexture = NULL;
+ }
+
+ if (mOffscreenRTView)
+ {
+ mOffscreenRTView->Release();
+ mOffscreenRTView = NULL;
+ }
+
+ if (mOffscreenSRView)
+ {
+ mOffscreenSRView->Release();
+ mOffscreenSRView = NULL;
+ }
+
+ if (mDepthStencilTexture)
+ {
+ mDepthStencilTexture->Release();
+ mDepthStencilTexture = NULL;
+ }
+
+ if (mDepthStencilDSView)
+ {
+ mDepthStencilDSView->Release();
+ mDepthStencilDSView = NULL;
+ }
+}
+
+EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHeight)
+{
+ ID3D11Device *device = mRenderer->getDevice();
+
+ ASSERT(device != NULL);
+
+ // D3D11 does not allow zero size textures
+ ASSERT(backbufferWidth >= 1);
+ ASSERT(backbufferHeight >= 1);
+
+ // Preserve the render target content
+ ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture;
+ if (previousOffscreenTexture)
+ {
+ previousOffscreenTexture->AddRef();
+ }
+ const int previousWidth = mWidth;
+ const int previousHeight = mHeight;
+
+ releaseOffscreenTexture();
+
+ // If the app passed in a share handle, open the resource
+ // See EGL_ANGLE_d3d_share_handle_client_buffer
+ if (mAppCreatedShareHandle)
+ {
+ ID3D11Resource *tempResource11;
+ HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource), (void**)&tempResource11);
+
+ if (FAILED(result))
+ {
+ ERR("Failed to open the swap chain pbuffer share handle: %08lX", result);
+ release();
+ return EGL_BAD_PARAMETER;
+ }
+
+ result = tempResource11->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&mOffscreenTexture);
+ tempResource11->Release();
+
+ if (FAILED(result))
+ {
+ ERR("Failed to query texture2d interface in pbuffer share handle: %08lX", result);
+ release();
+ return EGL_BAD_PARAMETER;
+ }
+
+ // Validate offscreen texture parameters
+ D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0};
+ mOffscreenTexture->GetDesc(&offscreenTextureDesc);
+
+ if (offscreenTextureDesc.Width != (UINT)backbufferWidth
+ || offscreenTextureDesc.Height != (UINT)backbufferHeight
+ || offscreenTextureDesc.Format != gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat)
+ || offscreenTextureDesc.MipLevels != 1
+ || offscreenTextureDesc.ArraySize != 1)
+ {
+ ERR("Invalid texture parameters in the shared offscreen texture pbuffer");
+ release();
+ return EGL_BAD_PARAMETER;
+ }
+ }
+ else
+ {
+ const bool useSharedResource = !mWindow && mRenderer->getShareHandleSupport();
+
+ D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0};
+ offscreenTextureDesc.Width = backbufferWidth;
+ offscreenTextureDesc.Height = backbufferHeight;
+ offscreenTextureDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat);
+ offscreenTextureDesc.MipLevels = 1;
+ offscreenTextureDesc.ArraySize = 1;
+ offscreenTextureDesc.SampleDesc.Count = 1;
+ offscreenTextureDesc.SampleDesc.Quality = 0;
+ offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT;
+ offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
+ offscreenTextureDesc.CPUAccessFlags = 0;
+ offscreenTextureDesc.MiscFlags = useSharedResource ? D3D11_RESOURCE_MISC_SHARED : 0;
+
+ HRESULT result = device->CreateTexture2D(&offscreenTextureDesc, NULL, &mOffscreenTexture);
+
+ if (FAILED(result))
+ {
+ ERR("Could not create offscreen texture: %08lX", result);
+ release();
+
+ if (d3d11::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+
+ d3d11::SetDebugName(mOffscreenTexture, "Offscreen texture");
+
+ // EGL_ANGLE_surface_d3d_texture_2d_share_handle requires that we store a share handle for the client
+ if (useSharedResource)
+ {
+ IDXGIResource *offscreenTextureResource = NULL;
+ result = mOffscreenTexture->QueryInterface(__uuidof(IDXGIResource), (void**)&offscreenTextureResource);
+
+ // Fall back to no share handle on failure
+ if (FAILED(result))
+ {
+ ERR("Could not query offscreen texture resource: %08lX", result);
+ }
+ else
+ {
+ result = offscreenTextureResource->GetSharedHandle(&mShareHandle);
+
+ if (FAILED(result))
+ {
+ mShareHandle = NULL;
+ ERR("Could not get offscreen texture shared handle: %08lX", result);
+ }
+ }
+ }
+ }
+
+ HRESULT result = device->CreateRenderTargetView(mOffscreenTexture, NULL, &mOffscreenRTView);
+
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mOffscreenRTView, "Offscreen render target");
+
+ result = device->CreateShaderResourceView(mOffscreenTexture, NULL, &mOffscreenSRView);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mOffscreenSRView, "Offscreen shader resource");
+
+ if (mDepthBufferFormat != GL_NONE)
+ {
+ D3D11_TEXTURE2D_DESC depthStencilDesc = {0};
+ depthStencilDesc.Width = backbufferWidth;
+ depthStencilDesc.Height = backbufferHeight;
+ depthStencilDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mDepthBufferFormat);
+ depthStencilDesc.MipLevels = 1;
+ depthStencilDesc.ArraySize = 1;
+ depthStencilDesc.SampleDesc.Count = 1;
+ depthStencilDesc.SampleDesc.Quality = 0;
+ depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
+ depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
+ depthStencilDesc.CPUAccessFlags = 0;
+ depthStencilDesc.MiscFlags = 0;
+
+ result = device->CreateTexture2D(&depthStencilDesc, NULL, &mDepthStencilTexture);
+ if (FAILED(result))
+ {
+ ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
+ release();
+
+ if (d3d11::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+ d3d11::SetDebugName(mDepthStencilTexture, "Depth stencil texture");
+
+ result = device->CreateDepthStencilView(mDepthStencilTexture, NULL, &mDepthStencilDSView);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mDepthStencilDSView, "Depth stencil view");
+ }
+
+ mWidth = backbufferWidth;
+ mHeight = backbufferHeight;
+
+ if (previousOffscreenTexture != NULL)
+ {
+ D3D11_BOX sourceBox = {0};
+ sourceBox.left = 0;
+ sourceBox.right = std::min(previousWidth, mWidth);
+ sourceBox.top = std::max(previousHeight - mHeight, 0);
+ sourceBox.bottom = previousHeight;
+ sourceBox.front = 0;
+ sourceBox.back = 1;
+
+ ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+ const int yoffset = std::max(mHeight - previousHeight, 0);
+ deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, previousOffscreenTexture, 0, &sourceBox);
+
+ previousOffscreenTexture->Release();
+
+ if (mSwapChain)
+ {
+ swapRect(0, 0, mWidth, mHeight);
+ }
+ }
+
+ return EGL_SUCCESS;
+}
+
+EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight)
+{
+ ID3D11Device *device = mRenderer->getDevice();
+
+ if (device == NULL)
+ {
+ return EGL_BAD_ACCESS;
+ }
+
+ // Can only call resize if we have already created our swap buffer and resources
+ ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView);
+
+ if (mBackBufferTexture)
+ {
+ mBackBufferTexture->Release();
+ mBackBufferTexture = NULL;
+ }
+
+ if (mBackBufferRTView)
+ {
+ mBackBufferRTView->Release();
+ mBackBufferRTView = NULL;
+ }
+
+ // Resize swap chain
+ DXGI_FORMAT backbufferDXGIFormat = gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat);
+ HRESULT result = mSwapChain->ResizeBuffers(2, backbufferWidth, backbufferHeight, backbufferDXGIFormat, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Error resizing swap chain buffers: 0x%08X", result);
+ release();
+
+ if (d3d11::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+
+ result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture);
+ ASSERT(SUCCEEDED(result));
+ if (SUCCEEDED(result))
+ {
+ d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture");
+ }
+
+ result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView);
+ ASSERT(SUCCEEDED(result));
+ if (SUCCEEDED(result))
+ {
+ d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target");
+ }
+
+ return resetOffscreenTexture(backbufferWidth, backbufferHeight);
+}
+
+EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
+{
+ ID3D11Device *device = mRenderer->getDevice();
+
+ if (device == NULL)
+ {
+ return EGL_BAD_ACCESS;
+ }
+
+ // Release specific resources to free up memory for the new render target, while the
+ // old render target still exists for the purpose of preserving its contents.
+ if (mSwapChain)
+ {
+ mSwapChain->Release();
+ mSwapChain = NULL;
+ }
+
+ if (mBackBufferTexture)
+ {
+ mBackBufferTexture->Release();
+ mBackBufferTexture = NULL;
+ }
+
+ if (mBackBufferRTView)
+ {
+ mBackBufferRTView->Release();
+ mBackBufferRTView = NULL;
+ }
+
+ mSwapInterval = static_cast<unsigned int>(swapInterval);
+ if (mSwapInterval > 4)
+ {
+ // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4] range
+ return EGL_BAD_PARAMETER;
+ }
+
+ // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains
+ if (backbufferWidth < 1 || backbufferHeight < 1)
+ {
+ releaseOffscreenTexture();
+ return EGL_SUCCESS;
+ }
+
+ if (mWindow)
+ {
+ // We cannot create a swap chain for an HWND that is owned by a different process
+ DWORD currentProcessId = GetCurrentProcessId();
+ DWORD wndProcessId;
+ GetWindowThreadProcessId(mWindow, &wndProcessId);
+
+ if (currentProcessId != wndProcessId)
+ {
+ ERR("Could not create swap chain, window owned by different process");
+ release();
+ return EGL_BAD_NATIVE_WINDOW;
+ }
+
+ IDXGIFactory *factory = mRenderer->getDxgiFactory();
+
+ DXGI_SWAP_CHAIN_DESC swapChainDesc = {0};
+ swapChainDesc.BufferCount = 2;
+ swapChainDesc.BufferDesc.Format = gl_d3d11::ConvertRenderbufferFormat(mBackBufferFormat);
+ swapChainDesc.BufferDesc.Width = backbufferWidth;
+ swapChainDesc.BufferDesc.Height = backbufferHeight;
+ 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;
+ swapChainDesc.Flags = 0;
+ swapChainDesc.OutputWindow = mWindow;
+ swapChainDesc.SampleDesc.Count = 1;
+ swapChainDesc.SampleDesc.Quality = 0;
+ swapChainDesc.Windowed = TRUE;
+
+ HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, &mSwapChain);
+
+ if (FAILED(result))
+ {
+ ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
+ release();
+
+ if (d3d11::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+
+ result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture");
+
+ result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target");
+ }
+
+ // If we are resizing the swap chain, we don't wish to recreate all the static resources
+ if (!mPassThroughResourcesInit)
+ {
+ mPassThroughResourcesInit = true;
+ initPassThroughResources();
+ }
+
+ return resetOffscreenTexture(backbufferWidth, backbufferHeight);
+}
+
+void SwapChain11::initPassThroughResources()
+{
+ ID3D11Device *device = mRenderer->getDevice();
+
+ ASSERT(device != NULL);
+
+ // Make sure our resources are all not allocated, when we create
+ ASSERT(mQuadVB == NULL && mPassThroughSampler == NULL);
+ ASSERT(mPassThroughIL == NULL && mPassThroughVS == NULL && mPassThroughPS == NULL);
+
+ D3D11_BUFFER_DESC vbDesc;
+ vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4;
+ vbDesc.Usage = D3D11_USAGE_DYNAMIC;
+ vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ vbDesc.MiscFlags = 0;
+ vbDesc.StructureByteStride = 0;
+
+ HRESULT result = device->CreateBuffer(&vbDesc, NULL, &mQuadVB);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mQuadVB, "Swap chain quad vertex buffer");
+
+ D3D11_SAMPLER_DESC samplerDesc;
+ samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+ samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.MipLODBias = 0.0f;
+ samplerDesc.MaxAnisotropy = 0;
+ samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+ samplerDesc.BorderColor[0] = 0.0f;
+ samplerDesc.BorderColor[1] = 0.0f;
+ samplerDesc.BorderColor[2] = 0.0f;
+ samplerDesc.BorderColor[3] = 0.0f;
+ samplerDesc.MinLOD = 0;
+ samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
+
+ result = device->CreateSamplerState(&samplerDesc, &mPassThroughSampler);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mPassThroughSampler, "Swap chain pass through sampler");
+
+ D3D11_INPUT_ELEMENT_DESC quadLayout[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+
+ result = device->CreateInputLayout(quadLayout, 2, g_VS_Passthrough, sizeof(g_VS_Passthrough), &mPassThroughIL);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mPassThroughIL, "Swap chain pass through layout");
+
+ result = device->CreateVertexShader(g_VS_Passthrough, sizeof(g_VS_Passthrough), NULL, &mPassThroughVS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mPassThroughVS, "Swap chain pass through vertex shader");
+
+ result = device->CreatePixelShader(g_PS_PassthroughRGBA, sizeof(g_PS_PassthroughRGBA), NULL, &mPassThroughPS);
+ ASSERT(SUCCEEDED(result));
+ d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader");
+}
+
+// parameters should be validated/clamped by caller
+EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ if (!mSwapChain)
+ {
+ return EGL_SUCCESS;
+ }
+
+ ID3D11Device *device = mRenderer->getDevice();
+ ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
+
+ // Set vertices
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ return EGL_BAD_ACCESS;
+ }
+
+ d3d11::PositionTexCoordVertex *vertices = static_cast<d3d11::PositionTexCoordVertex*>(mappedResource.pData);
+
+ // Create a quad in homogeneous coordinates
+ float x1 = (x / float(mWidth)) * 2.0f - 1.0f;
+ float y1 = (y / float(mHeight)) * 2.0f - 1.0f;
+ float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f;
+ float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f;
+
+ float u1 = x / float(mWidth);
+ float v1 = y / float(mHeight);
+ float u2 = (x + width) / float(mWidth);
+ float v2 = (y + height) / float(mHeight);
+
+ d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v1);
+ d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2);
+ d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1);
+ d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2);
+
+ deviceContext->Unmap(mQuadVB, 0);
+
+ static UINT stride = sizeof(d3d11::PositionTexCoordVertex);
+ static UINT startIdx = 0;
+ deviceContext->IASetVertexBuffers(0, 1, &mQuadVB, &stride, &startIdx);
+
+ // Apply state
+ deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF);
+
+ static const float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ deviceContext->OMSetBlendState(NULL, blendFactor, 0xFFFFFFF);
+
+ deviceContext->RSSetState(NULL);
+
+ // Apply shaders
+ deviceContext->IASetInputLayout(mPassThroughIL);
+ deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ deviceContext->VSSetShader(mPassThroughVS, NULL, 0);
+ deviceContext->PSSetShader(mPassThroughPS, NULL, 0);
+ deviceContext->GSSetShader(NULL, NULL, 0);
+
+ // Apply render targets
+ mRenderer->setOneTimeRenderTarget(mBackBufferRTView);
+
+ // Set the viewport
+ D3D11_VIEWPORT viewport;
+ viewport.TopLeftX = 0;
+ viewport.TopLeftY = 0;
+ viewport.Width = mWidth;
+ viewport.Height = mHeight;
+ viewport.MinDepth = 0.0f;
+ viewport.MaxDepth = 1.0f;
+ deviceContext->RSSetViewports(1, &viewport);
+
+ // Apply textures
+ deviceContext->PSSetShaderResources(0, 1, &mOffscreenSRView);
+ deviceContext->PSSetSamplers(0, 1, &mPassThroughSampler);
+
+ // Draw
+ deviceContext->Draw(4, 0);
+ result = mSwapChain->Present(mSwapInterval, 0);
+
+ if (result == DXGI_ERROR_DEVICE_REMOVED)
+ {
+ HRESULT removedReason = device->GetDeviceRemovedReason();
+ ERR("Present failed: the D3D11 device was removed: 0x%08X", removedReason);
+ return EGL_CONTEXT_LOST;
+ }
+ else if (result == DXGI_ERROR_DEVICE_RESET)
+ {
+ ERR("Present failed: the D3D11 device was reset from a bad command.");
+ return EGL_CONTEXT_LOST;
+ }
+ else if (FAILED(result))
+ {
+ ERR("Present failed with error code 0x%08X", result);
+ }
+
+ // Unbind
+ static ID3D11ShaderResourceView *const nullSRV = NULL;
+ deviceContext->PSSetShaderResources(0, 1, &nullSRV);
+
+ mRenderer->unapplyRenderTargets();
+ mRenderer->markAllStateDirty();
+
+ return EGL_SUCCESS;
+}
+
+// Increments refcount on texture.
+// caller must Release() the returned texture
+ID3D11Texture2D *SwapChain11::getOffscreenTexture()
+{
+ if (mOffscreenTexture)
+ {
+ mOffscreenTexture->AddRef();
+ }
+
+ return mOffscreenTexture;
+}
+
+// Increments refcount on view.
+// caller must Release() the returned view
+ID3D11RenderTargetView *SwapChain11::getRenderTarget()
+{
+ if (mOffscreenRTView)
+ {
+ mOffscreenRTView->AddRef();
+ }
+
+ return mOffscreenRTView;
+}
+
+// Increments refcount on view.
+// caller must Release() the returned view
+ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource()
+{
+ if (mOffscreenSRView)
+ {
+ mOffscreenSRView->AddRef();
+ }
+
+ return mOffscreenSRView;
+}
+
+// Increments refcount on view.
+// caller must Release() the returned view
+ID3D11DepthStencilView *SwapChain11::getDepthStencil()
+{
+ if (mDepthStencilDSView)
+ {
+ mDepthStencilDSView->AddRef();
+ }
+
+ return mDepthStencilDSView;
+}
+
+ID3D11Texture2D *SwapChain11::getDepthStencilTexture()
+{
+ if (mDepthStencilTexture)
+ {
+ mDepthStencilTexture->AddRef();
+ }
+
+ return mDepthStencilTexture;
+}
+
+SwapChain11 *SwapChain11::makeSwapChain11(SwapChain *swapChain)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain11*, swapChain));
+ return static_cast<rx::SwapChain11*>(swapChain);
+}
+
+void SwapChain11::recreate()
+{
+ // possibly should use this method instead of reset
+}
+
+}
diff --git a/src/libGLESv2/renderer/SwapChain11.h b/src/libGLESv2/renderer/SwapChain11.h
new file mode 100644
index 00000000..80010460
--- /dev/null
+++ b/src/libGLESv2/renderer/SwapChain11.h
@@ -0,0 +1,78 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// SwapChain11.h: Defines a back-end specific class for the D3D11 swap chain.
+
+#ifndef LIBGLESV2_RENDERER_SWAPCHAIN11_H_
+#define LIBGLESV2_RENDERER_SWAPCHAIN11_H_
+
+#include "common/angleutils.h"
+#include "libGLESv2/renderer/SwapChain.h"
+
+namespace rx
+{
+class Renderer11;
+
+class SwapChain11 : public SwapChain
+{
+ public:
+ SwapChain11(Renderer11 *renderer, HWND window, HANDLE shareHandle,
+ GLenum backBufferFormat, GLenum depthBufferFormat);
+ virtual ~SwapChain11();
+
+ EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight);
+ virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval);
+ virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height);
+ virtual void recreate();
+
+ virtual ID3D11Texture2D *getOffscreenTexture();
+ virtual ID3D11RenderTargetView *getRenderTarget();
+ virtual ID3D11ShaderResourceView *getRenderTargetShaderResource();
+
+ virtual ID3D11Texture2D *getDepthStencilTexture();
+ virtual ID3D11DepthStencilView *getDepthStencil();
+
+ EGLint getWidth() const { return mWidth; }
+ EGLint getHeight() const { return mHeight; }
+
+ static SwapChain11 *makeSwapChain11(SwapChain *swapChain);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SwapChain11);
+
+ void release();
+ void initPassThroughResources();
+ void releaseOffscreenTexture();
+ EGLint resetOffscreenTexture(int backbufferWidth, int backbufferHeight);
+
+ Renderer11 *mRenderer;
+ EGLint mHeight;
+ EGLint mWidth;
+ bool mAppCreatedShareHandle;
+ unsigned int mSwapInterval;
+ bool mPassThroughResourcesInit;
+
+ IDXGISwapChain *mSwapChain;
+
+ ID3D11Texture2D *mBackBufferTexture;
+ ID3D11RenderTargetView *mBackBufferRTView;
+
+ ID3D11Texture2D *mOffscreenTexture;
+ ID3D11RenderTargetView *mOffscreenRTView;
+ ID3D11ShaderResourceView *mOffscreenSRView;
+
+ ID3D11Texture2D *mDepthStencilTexture;
+ ID3D11DepthStencilView *mDepthStencilDSView;
+
+ ID3D11Buffer *mQuadVB;
+ ID3D11SamplerState *mPassThroughSampler;
+ ID3D11InputLayout *mPassThroughIL;
+ ID3D11VertexShader *mPassThroughVS;
+ ID3D11PixelShader *mPassThroughPS;
+};
+
+}
+#endif // LIBGLESV2_RENDERER_SWAPCHAIN11_H_
diff --git a/src/libGLESv2/renderer/SwapChain9.cpp b/src/libGLESv2/renderer/SwapChain9.cpp
new file mode 100644
index 00000000..0324d019
--- /dev/null
+++ b/src/libGLESv2/renderer/SwapChain9.cpp
@@ -0,0 +1,434 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain.
+
+#include "libGLESv2/renderer/SwapChain9.h"
+#include "libGLESv2/renderer/renderer9_utils.h"
+#include "libGLESv2/renderer/Renderer9.h"
+
+namespace rx
+{
+
+SwapChain9::SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle,
+ GLenum backBufferFormat, GLenum depthBufferFormat)
+ : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat)
+{
+ mSwapChain = NULL;
+ mBackBuffer = NULL;
+ mDepthStencil = NULL;
+ mRenderTarget = NULL;
+ mOffscreenTexture = NULL;
+ mWidth = -1;
+ mHeight = -1;
+ mSwapInterval = -1;
+}
+
+SwapChain9::~SwapChain9()
+{
+ release();
+}
+
+void SwapChain9::release()
+{
+ if (mSwapChain)
+ {
+ mSwapChain->Release();
+ mSwapChain = NULL;
+ }
+
+ if (mBackBuffer)
+ {
+ mBackBuffer->Release();
+ mBackBuffer = NULL;
+ }
+
+ if (mDepthStencil)
+ {
+ mDepthStencil->Release();
+ mDepthStencil = NULL;
+ }
+
+ if (mRenderTarget)
+ {
+ mRenderTarget->Release();
+ mRenderTarget = NULL;
+ }
+
+ if (mOffscreenTexture)
+ {
+ mOffscreenTexture->Release();
+ mOffscreenTexture = NULL;
+ }
+
+ if (mWindow)
+ mShareHandle = NULL;
+}
+
+static DWORD convertInterval(EGLint interval)
+{
+ switch(interval)
+ {
+ case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
+ case 1: return D3DPRESENT_INTERVAL_ONE;
+ case 2: return D3DPRESENT_INTERVAL_TWO;
+ case 3: return D3DPRESENT_INTERVAL_THREE;
+ case 4: return D3DPRESENT_INTERVAL_FOUR;
+ default: UNREACHABLE();
+ }
+
+ return D3DPRESENT_INTERVAL_DEFAULT;
+}
+
+EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight)
+{
+ // D3D9 does not support resizing swap chains without recreating them
+ return reset(backbufferWidth, backbufferHeight, mSwapInterval);
+}
+
+EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval)
+{
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ if (device == NULL)
+ {
+ return EGL_BAD_ACCESS;
+ }
+
+ // Evict all non-render target textures to system memory and release all resources
+ // before reallocating them to free up as much video memory as possible.
+ device->EvictManagedResources();
+
+ HRESULT result;
+
+ // Release specific resources to free up memory for the new render target, while the
+ // old render target still exists for the purpose of preserving its contents.
+ if (mSwapChain)
+ {
+ mSwapChain->Release();
+ mSwapChain = NULL;
+ }
+
+ if (mBackBuffer)
+ {
+ mBackBuffer->Release();
+ mBackBuffer = NULL;
+ }
+
+ if (mOffscreenTexture)
+ {
+ mOffscreenTexture->Release();
+ mOffscreenTexture = NULL;
+ }
+
+ if (mDepthStencil)
+ {
+ mDepthStencil->Release();
+ mDepthStencil = NULL;
+ }
+
+ HANDLE *pShareHandle = NULL;
+ if (!mWindow && mRenderer->getShareHandleSupport())
+ {
+ pShareHandle = &mShareHandle;
+ }
+
+ result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET,
+ gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat), D3DPOOL_DEFAULT,
+ &mOffscreenTexture, pShareHandle);
+ if (FAILED(result))
+ {
+ ERR("Could not create offscreen texture: %08lX", result);
+ release();
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+
+ IDirect3DSurface9 *oldRenderTarget = mRenderTarget;
+
+ result = mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
+ ASSERT(SUCCEEDED(result));
+
+ if (oldRenderTarget)
+ {
+ RECT rect =
+ {
+ 0, 0,
+ mWidth, mHeight
+ };
+
+ if (rect.right > static_cast<LONG>(backbufferWidth))
+ {
+ rect.right = backbufferWidth;
+ }
+
+ if (rect.bottom > static_cast<LONG>(backbufferHeight))
+ {
+ rect.bottom = backbufferHeight;
+ }
+
+ mRenderer->endScene();
+
+ result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE);
+ ASSERT(SUCCEEDED(result));
+
+ oldRenderTarget->Release();
+ }
+
+ if (mWindow)
+ {
+ D3DPRESENT_PARAMETERS presentParameters = {0};
+ presentParameters.AutoDepthStencilFormat = gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat);
+ presentParameters.BackBufferCount = 1;
+ presentParameters.BackBufferFormat = gl_d3d9::ConvertRenderbufferFormat(mBackBufferFormat);
+ presentParameters.EnableAutoDepthStencil = FALSE;
+ presentParameters.Flags = 0;
+ presentParameters.hDeviceWindow = mWindow;
+ presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented
+ presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented
+ presentParameters.PresentationInterval = convertInterval(swapInterval);
+ presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ presentParameters.Windowed = TRUE;
+ presentParameters.BackBufferWidth = backbufferWidth;
+ presentParameters.BackBufferHeight = backbufferHeight;
+
+ // http://crbug.com/140239
+ // http://crbug.com/143434
+ //
+ // Some AMD/Intel switchable systems / drivers appear to round swap chain surfaces to a multiple of 64 pixels in width
+ // when using the integrated Intel. This rounds the width up rather than down.
+ //
+ // Some non-switchable AMD GPUs / drivers do not respect the source rectangle to Present. Therefore, when the vendor ID
+ // is not Intel, the back buffer width must be exactly the same width as the window or horizontal scaling will occur.
+ if (mRenderer->getAdapterVendor() == VENDOR_ID_INTEL)
+ {
+ presentParameters.BackBufferWidth = (presentParameters.BackBufferWidth + 63) / 64 * 64;
+ }
+
+ result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL || result == D3DERR_DEVICELOST);
+
+ ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
+ release();
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+
+ result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
+ ASSERT(SUCCEEDED(result));
+ InvalidateRect(mWindow, NULL, FALSE);
+ }
+
+ if (mDepthBufferFormat != GL_NONE)
+ {
+ result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight,
+ gl_d3d9::ConvertRenderbufferFormat(mDepthBufferFormat),
+ D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_INVALIDCALL);
+
+ ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result);
+ release();
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+ else
+ {
+ return EGL_BAD_ALLOC;
+ }
+ }
+ }
+
+ mWidth = backbufferWidth;
+ mHeight = backbufferHeight;
+ mSwapInterval = swapInterval;
+
+ return EGL_SUCCESS;
+}
+
+// parameters should be validated/clamped by caller
+EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ if (!mSwapChain)
+ {
+ return EGL_SUCCESS;
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+
+ // Disable all pipeline operations
+ device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
+ device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
+ device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
+ device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
+ device->SetPixelShader(NULL);
+ device->SetVertexShader(NULL);
+
+ device->SetRenderTarget(0, mBackBuffer);
+ device->SetDepthStencilSurface(NULL);
+
+ device->SetTexture(0, mOffscreenTexture);
+ device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+ device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
+
+ D3DVIEWPORT9 viewport = {0, 0, mWidth, mHeight, 0.0f, 1.0f};
+ device->SetViewport(&viewport);
+
+ float x1 = x - 0.5f;
+ float y1 = (mHeight - y - height) - 0.5f;
+ float x2 = (x + width) - 0.5f;
+ float y2 = (mHeight - y) - 0.5f;
+
+ float u1 = x / float(mWidth);
+ float v1 = y / float(mHeight);
+ float u2 = (x + width) / float(mWidth);
+ float v2 = (y + height) / float(mHeight);
+
+ float quad[4][6] = {{x1, y1, 0.0f, 1.0f, u1, v2},
+ {x2, y1, 0.0f, 1.0f, u2, v2},
+ {x2, y2, 0.0f, 1.0f, u2, v1},
+ {x1, y2, 0.0f, 1.0f, u1, v1}}; // x, y, z, rhw, u, v
+
+ mRenderer->startScene();
+ device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float));
+ mRenderer->endScene();
+
+ device->SetTexture(0, NULL);
+
+ RECT rect =
+ {
+ x, mHeight - y - height,
+ x + width, mHeight - y
+ };
+
+ HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0);
+
+ mRenderer->markAllStateDirty();
+
+ if (d3d9::isDeviceLostError(result))
+ {
+ return EGL_CONTEXT_LOST;
+ }
+
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
+ {
+ return EGL_BAD_ALLOC;
+ }
+
+ ASSERT(SUCCEEDED(result));
+
+ return EGL_SUCCESS;
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+IDirect3DSurface9 *SwapChain9::getRenderTarget()
+{
+ if (mRenderTarget)
+ {
+ mRenderTarget->AddRef();
+ }
+
+ return mRenderTarget;
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+IDirect3DSurface9 *SwapChain9::getDepthStencil()
+{
+ if (mDepthStencil)
+ {
+ mDepthStencil->AddRef();
+ }
+
+ return mDepthStencil;
+}
+
+// Increments refcount on texture.
+// caller must Release() the returned texture
+IDirect3DTexture9 *SwapChain9::getOffscreenTexture()
+{
+ if (mOffscreenTexture)
+ {
+ mOffscreenTexture->AddRef();
+ }
+
+ return mOffscreenTexture;
+}
+
+SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain9*, swapChain));
+ return static_cast<rx::SwapChain9*>(swapChain);
+}
+
+void SwapChain9::recreate()
+{
+ if (!mSwapChain)
+ {
+ return;
+ }
+
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+ if (device == NULL)
+ {
+ return;
+ }
+
+ D3DPRESENT_PARAMETERS presentParameters;
+ HRESULT result = mSwapChain->GetPresentParameters(&presentParameters);
+ ASSERT(SUCCEEDED(result));
+
+ IDirect3DSwapChain9* newSwapChain = NULL;
+ result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain);
+ if (FAILED(result))
+ {
+ return;
+ }
+
+ mSwapChain->Release();
+ mSwapChain = newSwapChain;
+
+ mBackBuffer->Release();
+ result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer);
+ ASSERT(SUCCEEDED(result));
+}
+
+}
diff --git a/src/libGLESv2/renderer/SwapChain9.h b/src/libGLESv2/renderer/SwapChain9.h
new file mode 100644
index 00000000..16a62bd8
--- /dev/null
+++ b/src/libGLESv2/renderer/SwapChain9.h
@@ -0,0 +1,55 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// SwapChain9.h: Defines a back-end specific class for the D3D9 swap chain.
+
+#ifndef LIBGLESV2_RENDERER_SWAPCHAIN9_H_
+#define LIBGLESV2_RENDERER_SWAPCHAIN9_H_
+
+#include "common/angleutils.h"
+#include "libGLESv2/renderer/SwapChain.h"
+
+namespace rx
+{
+class Renderer9;
+
+class SwapChain9 : public SwapChain
+{
+ public:
+ SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle,
+ GLenum backBufferFormat, GLenum depthBufferFormat);
+ virtual ~SwapChain9();
+
+ EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight);
+ virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval);
+ virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height);
+ virtual void recreate();
+
+ virtual IDirect3DSurface9 *getRenderTarget();
+ virtual IDirect3DSurface9 *getDepthStencil();
+ virtual IDirect3DTexture9 *getOffscreenTexture();
+
+ static SwapChain9 *makeSwapChain9(SwapChain *swapChain);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SwapChain9);
+
+ void release();
+
+ Renderer9 *mRenderer;
+ EGLint mHeight;
+ EGLint mWidth;
+ EGLint mSwapInterval;
+
+ IDirect3DSwapChain9 *mSwapChain;
+ IDirect3DSurface9 *mBackBuffer;
+ IDirect3DSurface9 *mRenderTarget;
+ IDirect3DSurface9 *mDepthStencil;
+ IDirect3DTexture9* mOffscreenTexture;
+};
+
+}
+#endif // LIBGLESV2_RENDERER_SWAPCHAIN9_H_
diff --git a/src/libGLESv2/renderer/TextureStorage.cpp b/src/libGLESv2/renderer/TextureStorage.cpp
new file mode 100644
index 00000000..00b316f1
--- /dev/null
+++ b/src/libGLESv2/renderer/TextureStorage.cpp
@@ -0,0 +1,122 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// TextureStorage.cpp: Implements the abstract rx::TextureStorageInterface class and its concrete derived
+// classes TextureStorageInterface2D and TextureStorageInterfaceCube, which act as the interface to the
+// GPU-side texture.
+
+#include "libGLESv2/renderer/TextureStorage.h"
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/Texture.h"
+
+#include "common/debug.h"
+
+namespace rx
+{
+unsigned int TextureStorageInterface::mCurrentTextureSerial = 1;
+
+TextureStorageInterface::TextureStorageInterface()
+ : mTextureSerial(issueTextureSerial()),
+ mInstance(NULL)
+{
+}
+
+TextureStorageInterface::~TextureStorageInterface()
+{
+ delete mInstance;
+}
+
+bool TextureStorageInterface::isRenderTarget() const
+{
+ return mInstance->isRenderTarget();
+}
+
+
+bool TextureStorageInterface::isManaged() const
+{
+ return mInstance->isManaged();
+}
+
+unsigned int TextureStorageInterface::getTextureSerial() const
+{
+ return mTextureSerial;
+}
+
+unsigned int TextureStorageInterface::issueTextureSerial()
+{
+ return mCurrentTextureSerial++;
+}
+
+int TextureStorageInterface::getLodOffset() const
+{
+ return mInstance->getLodOffset();
+}
+
+
+int TextureStorageInterface::levelCount()
+{
+ return mInstance->levelCount();
+}
+
+TextureStorageInterface2D::TextureStorageInterface2D(Renderer *renderer, SwapChain *swapchain)
+ : mRenderTargetSerial(gl::RenderbufferStorage::issueSerial())
+{
+ mInstance = renderer->createTextureStorage2D(swapchain);
+}
+
+TextureStorageInterface2D::TextureStorageInterface2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
+ : mRenderTargetSerial(gl::RenderbufferStorage::issueSerial())
+{
+ mInstance = renderer->createTextureStorage2D(levels, internalformat, usage, forceRenderable, width, height);
+}
+
+TextureStorageInterface2D::~TextureStorageInterface2D()
+{
+}
+
+RenderTarget *TextureStorageInterface2D::getRenderTarget() const
+{
+ return mInstance->getRenderTarget();
+}
+
+void TextureStorageInterface2D::generateMipmap(int level)
+{
+ mInstance->generateMipmap(level);
+}
+
+unsigned int TextureStorageInterface2D::getRenderTargetSerial(GLenum target) const
+{
+ return mRenderTargetSerial;
+}
+
+TextureStorageInterfaceCube::TextureStorageInterfaceCube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
+ : mFirstRenderTargetSerial(gl::RenderbufferStorage::issueCubeSerials())
+{
+ mInstance = renderer->createTextureStorageCube(levels, internalformat, usage, forceRenderable, size);
+}
+
+TextureStorageInterfaceCube::~TextureStorageInterfaceCube()
+{
+}
+
+RenderTarget *TextureStorageInterfaceCube::getRenderTarget(GLenum faceTarget) const
+{
+ return mInstance->getRenderTarget(faceTarget);
+}
+
+void TextureStorageInterfaceCube::generateMipmap(int face, int level)
+{
+ mInstance->generateMipmap(face, level);
+}
+
+unsigned int TextureStorageInterfaceCube::getRenderTargetSerial(GLenum target) const
+{
+ return mFirstRenderTargetSerial + gl::TextureCubeMap::faceIndex(target);
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/TextureStorage.h b/src/libGLESv2/renderer/TextureStorage.h
new file mode 100644
index 00000000..edddb75f
--- /dev/null
+++ b/src/libGLESv2/renderer/TextureStorage.h
@@ -0,0 +1,110 @@
+//
+// 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.
+//
+
+// TextureStorage.h: Defines the abstract rx::TextureStorageInterface class and its concrete derived
+// classes TextureStorageInterface2D and TextureStorageInterfaceCube, which act as the interface to the
+// GPU-side texture.
+
+#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE_H_
+#define LIBGLESV2_RENDERER_TEXTURESTORAGE_H_
+
+#include "common/debug.h"
+
+namespace rx
+{
+class Renderer;
+class SwapChain;
+class RenderTarget;
+class Blit;
+
+class TextureStorage
+{
+ public:
+ TextureStorage() {};
+ virtual ~TextureStorage() {};
+
+ virtual int getLodOffset() const = 0;
+ virtual bool isRenderTarget() const = 0;
+ virtual bool isManaged() const = 0;
+ virtual int levelCount() = 0;
+
+ virtual RenderTarget *getRenderTarget() = 0;
+ virtual RenderTarget *getRenderTarget(GLenum faceTarget) = 0;
+ virtual void generateMipmap(int level) = 0;
+ virtual void generateMipmap(int face, int level) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorage);
+
+};
+
+class TextureStorageInterface
+{
+ public:
+ TextureStorageInterface();
+ virtual ~TextureStorageInterface();
+
+ TextureStorage *getStorageInstance() { return mInstance; }
+
+ unsigned int getTextureSerial() const;
+ virtual unsigned int getRenderTargetSerial(GLenum target) const = 0;
+
+ virtual int getLodOffset() const;
+ virtual bool isRenderTarget() const;
+ virtual bool isManaged() const;
+ virtual int levelCount();
+
+ protected:
+ TextureStorage *mInstance;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorageInterface);
+
+ const unsigned int mTextureSerial;
+ static unsigned int issueTextureSerial();
+
+ static unsigned int mCurrentTextureSerial;
+};
+
+class TextureStorageInterface2D : public TextureStorageInterface
+{
+ public:
+ TextureStorageInterface2D(Renderer *renderer, SwapChain *swapchain);
+ TextureStorageInterface2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height);
+ virtual ~TextureStorageInterface2D();
+
+ void generateMipmap(int level);
+ RenderTarget *getRenderTarget() const;
+
+ virtual unsigned int getRenderTargetSerial(GLenum target) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorageInterface2D);
+
+ const unsigned int mRenderTargetSerial;
+};
+
+class TextureStorageInterfaceCube : public TextureStorageInterface
+{
+ public:
+ TextureStorageInterfaceCube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size);
+ virtual ~TextureStorageInterfaceCube();
+
+ void generateMipmap(int face, int level);
+ RenderTarget *getRenderTarget(GLenum faceTarget) const;
+
+ virtual unsigned int getRenderTargetSerial(GLenum target) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorageInterfaceCube);
+
+ const unsigned int mFirstRenderTargetSerial;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE_H_
+
diff --git a/src/libGLESv2/renderer/TextureStorage11.cpp b/src/libGLESv2/renderer/TextureStorage11.cpp
new file mode 100644
index 00000000..408b48eb
--- /dev/null
+++ b/src/libGLESv2/renderer/TextureStorage11.cpp
@@ -0,0 +1,667 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// TextureStorage11.cpp: Implements the abstract rx::TextureStorage11 class and its concrete derived
+// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture.
+
+#include "libGLESv2/renderer/TextureStorage11.h"
+
+#include "libGLESv2/renderer/Renderer11.h"
+#include "libGLESv2/renderer/RenderTarget11.h"
+#include "libGLESv2/renderer/SwapChain11.h"
+#include "libGLESv2/renderer/renderer11_utils.h"
+
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/main.h"
+
+namespace rx
+{
+
+TextureStorage11::TextureStorage11(Renderer *renderer, UINT bindFlags)
+ : mBindFlags(bindFlags),
+ mLodOffset(0),
+ mMipLevels(0),
+ mTexture(NULL),
+ mTextureFormat(DXGI_FORMAT_UNKNOWN),
+ mShaderResourceFormat(DXGI_FORMAT_UNKNOWN),
+ mRenderTargetFormat(DXGI_FORMAT_UNKNOWN),
+ mDepthStencilFormat(DXGI_FORMAT_UNKNOWN),
+ mSRV(NULL),
+ mTextureWidth(0),
+ mTextureHeight(0)
+{
+ mRenderer = Renderer11::makeRenderer11(renderer);
+}
+
+TextureStorage11::~TextureStorage11()
+{
+}
+
+TextureStorage11 *TextureStorage11::makeTextureStorage11(TextureStorage *storage)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11*, storage));
+ return static_cast<TextureStorage11*>(storage);
+}
+
+DWORD TextureStorage11::GetTextureBindFlags(DXGI_FORMAT format, GLenum glusage, bool forceRenderable)
+{
+ UINT bindFlags = D3D11_BIND_SHADER_RESOURCE;
+
+ if (d3d11::IsDepthStencilFormat(format))
+ {
+ bindFlags |= D3D11_BIND_DEPTH_STENCIL;
+ }
+ else if(forceRenderable || (TextureStorage11::IsTextureFormatRenderable(format) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
+ {
+ bindFlags |= D3D11_BIND_RENDER_TARGET;
+ }
+ return bindFlags;
+}
+
+bool TextureStorage11::IsTextureFormatRenderable(DXGI_FORMAT format)
+{
+ switch(format)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ case DXGI_FORMAT_A8_UNORM:
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ case DXGI_FORMAT_R8_UNORM:
+ case DXGI_FORMAT_R8G8_UNORM:
+ case DXGI_FORMAT_R16_FLOAT:
+ case DXGI_FORMAT_R16G16_FLOAT:
+ return true;
+ case DXGI_FORMAT_BC1_UNORM:
+ case DXGI_FORMAT_BC2_UNORM:
+ case DXGI_FORMAT_BC3_UNORM:
+ case DXGI_FORMAT_R32G32B32_FLOAT: // not renderable on all devices
+ return false;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+UINT TextureStorage11::getBindFlags() const
+{
+ return mBindFlags;
+}
+
+ID3D11Texture2D *TextureStorage11::getBaseTexture() const
+{
+ return mTexture;
+}
+
+int TextureStorage11::getLodOffset() const
+{
+ return mLodOffset;
+}
+
+bool TextureStorage11::isRenderTarget() const
+{
+ return (mBindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL)) != 0;
+}
+
+bool TextureStorage11::isManaged() const
+{
+ return false;
+}
+
+int TextureStorage11::levelCount()
+{
+ int levels = 0;
+ if (getBaseTexture())
+ {
+ levels = mMipLevels - getLodOffset();
+ }
+ return levels;
+}
+
+UINT TextureStorage11::getSubresourceIndex(int level, int faceIndex)
+{
+ UINT index = 0;
+ if (getBaseTexture())
+ {
+ index = D3D11CalcSubresource(level, faceIndex, mMipLevels);
+ }
+ return index;
+}
+
+bool TextureStorage11::updateSubresourceLevel(ID3D11Texture2D *srcTexture, unsigned int sourceSubresource,
+ int level, int face, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height)
+{
+ if (srcTexture)
+ {
+ // Round up the width and height to the nearest multiple of dimension alignment
+ unsigned int dimensionAlignment = d3d11::GetTextureFormatDimensionAlignment(mTextureFormat);
+ width = width + dimensionAlignment - 1 - (width - 1) % dimensionAlignment;
+ height = height + dimensionAlignment - 1 - (height - 1) % dimensionAlignment;
+
+ D3D11_BOX srcBox;
+ srcBox.left = xoffset;
+ srcBox.top = yoffset;
+ srcBox.right = xoffset + width;
+ srcBox.bottom = yoffset + height;
+ srcBox.front = 0;
+ srcBox.back = 1;
+
+ ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+
+ ASSERT(getBaseTexture());
+ context->CopySubresourceRegion(getBaseTexture(), getSubresourceIndex(level + mLodOffset, face),
+ xoffset, yoffset, 0, srcTexture, sourceSubresource, &srcBox);
+ return true;
+ }
+
+ return false;
+}
+
+void TextureStorage11::generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest)
+{
+ if (source && dest)
+ {
+ ID3D11ShaderResourceView *sourceSRV = source->getShaderResourceView();
+ ID3D11RenderTargetView *destRTV = dest->getRenderTargetView();
+
+ if (sourceSRV && destRTV)
+ {
+ gl::Rectangle sourceArea;
+ sourceArea.x = 0;
+ sourceArea.y = 0;
+ sourceArea.width = source->getWidth();
+ sourceArea.height = source->getHeight();
+
+ gl::Rectangle destArea;
+ destArea.x = 0;
+ destArea.y = 0;
+ destArea.width = dest->getWidth();
+ destArea.height = dest->getHeight();
+
+ mRenderer->copyTexture(sourceSRV, sourceArea, source->getWidth(), source->getHeight(),
+ destRTV, destArea, dest->getWidth(), dest->getHeight(),
+ GL_RGBA);
+ }
+ }
+}
+
+TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain)
+ : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE)
+{
+ mTexture = swapchain->getOffscreenTexture();
+ mSRV = swapchain->getRenderTargetShaderResource();
+
+ for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ mRenderTarget[i] = NULL;
+ }
+
+ D3D11_TEXTURE2D_DESC texDesc;
+ mTexture->GetDesc(&texDesc);
+ mMipLevels = texDesc.MipLevels;
+ mTextureFormat = texDesc.Format;
+ mTextureWidth = texDesc.Width;
+ mTextureHeight = texDesc.Height;
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ mSRV->GetDesc(&srvDesc);
+ mShaderResourceFormat = srvDesc.Format;
+
+ ID3D11RenderTargetView* offscreenRTV = swapchain->getRenderTarget();
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
+ offscreenRTV->GetDesc(&rtvDesc);
+ mRenderTargetFormat = rtvDesc.Format;
+ offscreenRTV->Release();
+
+ mDepthStencilFormat = DXGI_FORMAT_UNKNOWN;
+}
+
+TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
+ : TextureStorage11(renderer, GetTextureBindFlags(gl_d3d11::ConvertTextureFormat(internalformat), usage, forceRenderable))
+{
+ for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ mRenderTarget[i] = NULL;
+ }
+
+ DXGI_FORMAT convertedFormat = gl_d3d11::ConvertTextureFormat(internalformat);
+ if (d3d11::IsDepthStencilFormat(convertedFormat))
+ {
+ mTextureFormat = d3d11::GetDepthTextureFormat(convertedFormat);
+ mShaderResourceFormat = d3d11::GetDepthShaderResourceFormat(convertedFormat);
+ mDepthStencilFormat = convertedFormat;
+ mRenderTargetFormat = DXGI_FORMAT_UNKNOWN;
+ }
+ else
+ {
+ mTextureFormat = convertedFormat;
+ mShaderResourceFormat = convertedFormat;
+ mDepthStencilFormat = DXGI_FORMAT_UNKNOWN;
+ mRenderTargetFormat = convertedFormat;
+ }
+
+ // 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 (width > 0 && height > 0)
+ {
+ // adjust size if needed for compressed textures
+ gl::MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset);
+
+ ID3D11Device *device = mRenderer->getDevice();
+
+ D3D11_TEXTURE2D_DESC desc;
+ desc.Width = width; // Compressed texture size constraints?
+ desc.Height = height;
+ desc.MipLevels = (levels > 0) ? levels + mLodOffset : 0;
+ desc.ArraySize = 1;
+ desc.Format = mTextureFormat;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = getBindFlags();
+ desc.CPUAccessFlags = 0;
+ desc.MiscFlags = 0;
+
+ HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture);
+
+ // this can happen from windows TDR
+ if (d3d11::isDeviceLostError(result))
+ {
+ mRenderer->notifyDeviceLost();
+ gl::error(GL_OUT_OF_MEMORY);
+ }
+ else if (FAILED(result))
+ {
+ ASSERT(result == E_OUTOFMEMORY);
+ ERR("Creating image failed.");
+ gl::error(GL_OUT_OF_MEMORY);
+ }
+ else
+ {
+ mTexture->GetDesc(&desc);
+ mMipLevels = desc.MipLevels;
+ mTextureWidth = desc.Width;
+ mTextureHeight = desc.Height;
+ }
+ }
+}
+
+TextureStorage11_2D::~TextureStorage11_2D()
+{
+ if (mTexture)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ }
+
+ if (mSRV)
+ {
+ mSRV->Release();
+ mSRV = NULL;
+ }
+
+ for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ delete mRenderTarget[i];
+ mRenderTarget[i] = NULL;
+ }
+}
+
+TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage));
+ return static_cast<TextureStorage11_2D*>(storage);
+}
+
+RenderTarget *TextureStorage11_2D::getRenderTarget(int level)
+{
+ if (level >= 0 && level < static_cast<int>(mMipLevels))
+ {
+ if (!mRenderTarget[level])
+ {
+ ID3D11Device *device = mRenderer->getDevice();
+ HRESULT result;
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ srvDesc.Format = mShaderResourceFormat;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MostDetailedMip = level;
+ srvDesc.Texture2D.MipLevels = 1;
+
+ ID3D11ShaderResourceView *srv;
+ result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL));
+ }
+ ASSERT(SUCCEEDED(result));
+
+ if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN)
+ {
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
+ rtvDesc.Format = mRenderTargetFormat;
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ rtvDesc.Texture2D.MipSlice = level;
+
+ ID3D11RenderTargetView *rtv;
+ result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ srv->Release();
+ return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL));
+ }
+ ASSERT(SUCCEEDED(result));
+
+ // RenderTarget11 expects to be the owner of the resources it is given but TextureStorage11
+ // also needs to keep a reference to the texture.
+ mTexture->AddRef();
+
+ mRenderTarget[level] = new RenderTarget11(mRenderer, rtv, mTexture, srv,
+ std::max(mTextureWidth >> level, 1U),
+ std::max(mTextureHeight >> level, 1U));
+ }
+ else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN)
+ {
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
+ dsvDesc.Format = mDepthStencilFormat;
+ dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
+ dsvDesc.Texture2D.MipSlice = level;
+ dsvDesc.Flags = 0;
+
+ ID3D11DepthStencilView *dsv;
+ result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ srv->Release();
+ return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL));
+ }
+ ASSERT(SUCCEEDED(result));
+
+ // RenderTarget11 expects to be the owner of the resources it is given but TextureStorage11
+ // also needs to keep a reference to the texture.
+ mTexture->AddRef();
+
+ mRenderTarget[level] = new RenderTarget11(mRenderer, dsv, mTexture, srv,
+ std::max(mTextureWidth >> level, 1U),
+ std::max(mTextureHeight >> level, 1U));
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ }
+
+ return mRenderTarget[level];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+ID3D11ShaderResourceView *TextureStorage11_2D::getSRV()
+{
+ if (!mSRV)
+ {
+ ID3D11Device *device = mRenderer->getDevice();
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ srvDesc.Format = mShaderResourceFormat;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = (mMipLevels == 0 ? -1 : mMipLevels);
+ srvDesc.Texture2D.MostDetailedMip = 0;
+
+ HRESULT result = device->CreateShaderResourceView(mTexture, &srvDesc, &mSRV);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11ShaderResourceView*>(NULL));
+ }
+ ASSERT(SUCCEEDED(result));
+ }
+
+ return mSRV;
+}
+
+void TextureStorage11_2D::generateMipmap(int level)
+{
+ RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(level - 1));
+ RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(level));
+
+ generateMipmapLayer(source, dest);
+}
+
+TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
+ : TextureStorage11(renderer, GetTextureBindFlags(gl_d3d11::ConvertTextureFormat(internalformat), usage, forceRenderable))
+{
+ for (unsigned int i = 0; i < 6; i++)
+ {
+ for (unsigned int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; j++)
+ {
+ mRenderTarget[i][j] = NULL;
+ }
+ }
+
+ DXGI_FORMAT convertedFormat = gl_d3d11::ConvertTextureFormat(internalformat);
+ if (d3d11::IsDepthStencilFormat(convertedFormat))
+ {
+ mTextureFormat = d3d11::GetDepthTextureFormat(convertedFormat);
+ mShaderResourceFormat = d3d11::GetDepthShaderResourceFormat(convertedFormat);
+ mDepthStencilFormat = convertedFormat;
+ mRenderTargetFormat = DXGI_FORMAT_UNKNOWN;
+ }
+ else
+ {
+ mTextureFormat = convertedFormat;
+ mShaderResourceFormat = convertedFormat;
+ mDepthStencilFormat = DXGI_FORMAT_UNKNOWN;
+ mRenderTargetFormat = convertedFormat;
+ }
+
+ // 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 (size > 0)
+ {
+ // adjust size if needed for compressed textures
+ int height = size;
+ gl::MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset);
+
+ ID3D11Device *device = mRenderer->getDevice();
+
+ D3D11_TEXTURE2D_DESC desc;
+ desc.Width = size;
+ desc.Height = size;
+ desc.MipLevels = (levels > 0) ? levels + mLodOffset : 0;
+ desc.ArraySize = 6;
+ desc.Format = mTextureFormat;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = getBindFlags();
+ desc.CPUAccessFlags = 0;
+ desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;
+
+ HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == E_OUTOFMEMORY);
+ ERR("Creating image failed.");
+ gl::error(GL_OUT_OF_MEMORY);
+ }
+ else
+ {
+ mTexture->GetDesc(&desc);
+ mMipLevels = desc.MipLevels;
+ mTextureWidth = desc.Width;
+ mTextureHeight = desc.Height;
+ }
+ }
+}
+
+TextureStorage11_Cube::~TextureStorage11_Cube()
+{
+ if (mTexture)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ }
+
+ if (mSRV)
+ {
+ mSRV->Release();
+ mSRV = NULL;
+ }
+
+ for (unsigned int i = 0; i < 6; i++)
+ {
+ for (unsigned int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; j++)
+ {
+ delete mRenderTarget[i][j];
+ mRenderTarget[i][j] = NULL;
+ }
+ }
+}
+
+TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage));
+ return static_cast<TextureStorage11_Cube*>(storage);
+}
+
+RenderTarget *TextureStorage11_Cube::getRenderTarget(GLenum faceTarget, int level)
+{
+ unsigned int faceIdx = gl::TextureCubeMap::faceIndex(faceTarget);
+ if (level >= 0 && level < static_cast<int>(mMipLevels))
+ {
+ if (!mRenderTarget[faceIdx][level])
+ {
+ ID3D11Device *device = mRenderer->getDevice();
+ HRESULT result;
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ srvDesc.Format = mShaderResourceFormat;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
+ srvDesc.Texture2DArray.MostDetailedMip = level;
+ srvDesc.Texture2DArray.MipLevels = 1;
+ srvDesc.Texture2DArray.FirstArraySlice = faceIdx;
+ srvDesc.Texture2DArray.ArraySize = 1;
+
+ ID3D11ShaderResourceView *srv;
+ result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL));
+ }
+ ASSERT(SUCCEEDED(result));
+
+ if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN)
+ {
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
+ rtvDesc.Format = mRenderTargetFormat;
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+ rtvDesc.Texture2DArray.MipSlice = level;
+ rtvDesc.Texture2DArray.FirstArraySlice = faceIdx;
+ rtvDesc.Texture2DArray.ArraySize = 1;
+
+ ID3D11RenderTargetView *rtv;
+ result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ srv->Release();
+ return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL));
+ }
+ ASSERT(SUCCEEDED(result));
+
+ // RenderTarget11 expects to be the owner of the resources it is given but TextureStorage11
+ // also needs to keep a reference to the texture.
+ mTexture->AddRef();
+
+ mRenderTarget[faceIdx][level] = new RenderTarget11(mRenderer, rtv, mTexture, srv,
+ std::max(mTextureWidth >> level, 1U),
+ std::max(mTextureHeight >> level, 1U));
+ }
+ else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN)
+ {
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
+ dsvDesc.Format = mRenderTargetFormat;
+ dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
+ dsvDesc.Texture2DArray.MipSlice = level;
+ dsvDesc.Texture2DArray.FirstArraySlice = faceIdx;
+ dsvDesc.Texture2DArray.ArraySize = 1;
+
+ ID3D11DepthStencilView *dsv;
+ result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ srv->Release();
+ return gl::error(GL_OUT_OF_MEMORY, static_cast<RenderTarget*>(NULL));
+ }
+ ASSERT(SUCCEEDED(result));
+
+ // RenderTarget11 expects to be the owner of the resources it is given but TextureStorage11
+ // also needs to keep a reference to the texture.
+ mTexture->AddRef();
+
+ mRenderTarget[faceIdx][level] = new RenderTarget11(mRenderer, dsv, mTexture, srv,
+ std::max(mTextureWidth >> level, 1U),
+ std::max(mTextureHeight >> level, 1U));
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ }
+
+ return mRenderTarget[faceIdx][level];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+ID3D11ShaderResourceView *TextureStorage11_Cube::getSRV()
+{
+ if (!mSRV)
+ {
+ ID3D11Device *device = mRenderer->getDevice();
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ srvDesc.Format = mShaderResourceFormat;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
+ srvDesc.TextureCube.MipLevels = (mMipLevels == 0 ? -1 : mMipLevels);
+ srvDesc.TextureCube.MostDetailedMip = 0;
+
+ HRESULT result = device->CreateShaderResourceView(mTexture, &srvDesc, &mSRV);
+
+ if (result == E_OUTOFMEMORY)
+ {
+ return gl::error(GL_OUT_OF_MEMORY, static_cast<ID3D11ShaderResourceView*>(NULL));
+ }
+ ASSERT(SUCCEEDED(result));
+ }
+
+ return mSRV;
+}
+
+void TextureStorage11_Cube::generateMipmap(int face, int level)
+{
+ RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level - 1));
+ RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level));
+
+ generateMipmapLayer(source, dest);
+}
+
+}
diff --git a/src/libGLESv2/renderer/TextureStorage11.h b/src/libGLESv2/renderer/TextureStorage11.h
new file mode 100644
index 00000000..3c5ded05
--- /dev/null
+++ b/src/libGLESv2/renderer/TextureStorage11.h
@@ -0,0 +1,120 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// TextureStorage11.h: Defines the abstract rx::TextureStorage11 class and its concrete derived
+// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture.
+
+#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_
+#define LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_
+
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/renderer/TextureStorage.h"
+
+namespace rx
+{
+class RenderTarget;
+class RenderTarget11;
+class Renderer;
+class Renderer11;
+class SwapChain11;
+
+class TextureStorage11 : public TextureStorage
+{
+ public:
+ TextureStorage11(Renderer *renderer, UINT bindFlags);
+ virtual ~TextureStorage11();
+
+ static TextureStorage11 *makeTextureStorage11(TextureStorage *storage);
+
+ static DWORD GetTextureBindFlags(DXGI_FORMAT d3dfmt, GLenum glusage, bool forceRenderable);
+ static bool IsTextureFormatRenderable(DXGI_FORMAT format);
+
+ UINT getBindFlags() const;
+
+ virtual ID3D11Texture2D *getBaseTexture() const;
+ virtual ID3D11ShaderResourceView *getSRV() = 0;
+ virtual RenderTarget *getRenderTarget() { return getRenderTarget(0); }
+ virtual RenderTarget *getRenderTarget(int level) { return NULL; }
+ virtual RenderTarget *getRenderTarget(GLenum faceTarget) { return getRenderTarget(faceTarget, 0); }
+ virtual RenderTarget *getRenderTarget(GLenum faceTarget, int level) { return NULL; }
+
+ virtual void generateMipmap(int level) {};
+ virtual void generateMipmap(int face, int level) {};
+
+ virtual int getLodOffset() const;
+ virtual bool isRenderTarget() const;
+ virtual bool isManaged() const;
+ virtual int levelCount();
+ UINT getSubresourceIndex(int level, int faceTarget);
+
+ bool updateSubresourceLevel(ID3D11Texture2D *texture, unsigned int sourceSubresource, int level,
+ int faceTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+
+ protected:
+ void generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest);
+
+ Renderer11 *mRenderer;
+ int mLodOffset;
+ unsigned int mMipLevels;
+
+ ID3D11Texture2D *mTexture;
+ DXGI_FORMAT mTextureFormat;
+ DXGI_FORMAT mShaderResourceFormat;
+ DXGI_FORMAT mRenderTargetFormat;
+ DXGI_FORMAT mDepthStencilFormat;
+ unsigned int mTextureWidth;
+ unsigned int mTextureHeight;
+
+ ID3D11ShaderResourceView *mSRV;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorage11);
+
+ const UINT mBindFlags;
+};
+
+class TextureStorage11_2D : public TextureStorage11
+{
+ public:
+ TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain);
+ TextureStorage11_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height);
+ virtual ~TextureStorage11_2D();
+
+ static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage);
+
+ virtual ID3D11ShaderResourceView *getSRV();
+ virtual RenderTarget *getRenderTarget(int level);
+
+ virtual void generateMipmap(int level);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2D);
+
+ RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+};
+
+class TextureStorage11_Cube : public TextureStorage11
+{
+ public:
+ TextureStorage11_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size);
+ virtual ~TextureStorage11_Cube();
+
+ static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage);
+
+ virtual ID3D11ShaderResourceView *getSRV();
+ virtual RenderTarget *getRenderTarget(GLenum faceTarget, int level);
+
+ virtual void generateMipmap(int face, int level);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorage11_Cube);
+
+ RenderTarget11 *mRenderTarget[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_
diff --git a/src/libGLESv2/renderer/TextureStorage9.cpp b/src/libGLESv2/renderer/TextureStorage9.cpp
new file mode 100644
index 00000000..8aa74a7c
--- /dev/null
+++ b/src/libGLESv2/renderer/TextureStorage9.cpp
@@ -0,0 +1,328 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived
+// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the
+// D3D9 texture.
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/renderer/Renderer9.h"
+#include "libGLESv2/renderer/TextureStorage9.h"
+#include "libGLESv2/renderer/SwapChain9.h"
+#include "libGLESv2/renderer/RenderTarget9.h"
+#include "libGLESv2/renderer/renderer9_utils.h"
+#include "libGLESv2/Texture.h"
+
+namespace rx
+{
+TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage)
+ : mLodOffset(0),
+ mRenderer(Renderer9::makeRenderer9(renderer)),
+ mD3DUsage(usage),
+ mD3DPool(mRenderer->getTexturePool(usage))
+{
+}
+
+TextureStorage9::~TextureStorage9()
+{
+}
+
+TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage));
+ return static_cast<TextureStorage9*>(storage);
+}
+
+DWORD TextureStorage9::GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable)
+{
+ DWORD d3dusage = 0;
+
+ if (d3dfmt == D3DFMT_INTZ)
+ {
+ d3dusage |= D3DUSAGE_DEPTHSTENCIL;
+ }
+ else if(forceRenderable || (TextureStorage9::IsTextureFormatRenderable(d3dfmt) && (glusage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE)))
+ {
+ d3dusage |= D3DUSAGE_RENDERTARGET;
+ }
+ return d3dusage;
+}
+
+bool TextureStorage9::IsTextureFormatRenderable(D3DFORMAT format)
+{
+ if (format == D3DFMT_INTZ)
+ {
+ return true;
+ }
+ switch(format)
+ {
+ case D3DFMT_L8:
+ case D3DFMT_A8L8:
+ case D3DFMT_DXT1:
+ case D3DFMT_DXT3:
+ case D3DFMT_DXT5:
+ return false;
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A16B16G16R16F:
+ case D3DFMT_A32B32G32R32F:
+ return true;
+ default:
+ UNREACHABLE();
+ }
+
+ return false;
+}
+
+bool TextureStorage9::isRenderTarget() const
+{
+ return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0;
+}
+
+bool TextureStorage9::isManaged() const
+{
+ return (mD3DPool == D3DPOOL_MANAGED);
+}
+
+D3DPOOL TextureStorage9::getPool() const
+{
+ return mD3DPool;
+}
+
+DWORD TextureStorage9::getUsage() const
+{
+ return mD3DUsage;
+}
+
+int TextureStorage9::getLodOffset() const
+{
+ return mLodOffset;
+}
+
+int TextureStorage9::levelCount()
+{
+ return getBaseTexture() ? getBaseTexture()->GetLevelCount() - getLodOffset() : 0;
+}
+
+TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain) : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
+{
+ IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
+ mTexture = surfaceTexture;
+ mRenderTarget = NULL;
+
+ initializeRenderTarget();
+}
+
+TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height)
+ : TextureStorage9(renderer, GetTextureUsage(Renderer9::makeRenderer9(renderer)->ConvertTextureInternalFormat(internalformat), usage, forceRenderable))
+{
+ mTexture = NULL;
+ mRenderTarget = NULL;
+ // 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 (width > 0 && height > 0)
+ {
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+ gl::MakeValidSize(false, gl::IsCompressed(internalformat), &width, &height, &mLodOffset);
+ HRESULT result = device->CreateTexture(width, height, levels ? levels + mLodOffset : 0, getUsage(),
+ mRenderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ initializeRenderTarget();
+}
+
+TextureStorage9_2D::~TextureStorage9_2D()
+{
+ if (mTexture)
+ {
+ mTexture->Release();
+ }
+
+ delete mRenderTarget;
+}
+
+TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage));
+ return static_cast<TextureStorage9_2D*>(storage);
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+IDirect3DSurface9 *TextureStorage9_2D::getSurfaceLevel(int level, bool dirty)
+{
+ IDirect3DSurface9 *surface = NULL;
+
+ if (mTexture)
+ {
+ HRESULT result = mTexture->GetSurfaceLevel(level + mLodOffset, &surface);
+ ASSERT(SUCCEEDED(result));
+
+ // With managed textures the driver needs to be informed of updates to the lower mipmap levels
+ if (level + mLodOffset != 0 && isManaged() && dirty)
+ {
+ mTexture->AddDirtyRect(NULL);
+ }
+ }
+
+ return surface;
+}
+
+RenderTarget *TextureStorage9_2D::getRenderTarget()
+{
+ return mRenderTarget;
+}
+
+void TextureStorage9_2D::generateMipmap(int level)
+{
+ IDirect3DSurface9 *upper = getSurfaceLevel(level - 1, false);
+ IDirect3DSurface9 *lower = getSurfaceLevel(level, true);
+
+ if (upper != NULL && lower != NULL)
+ {
+ mRenderer->boxFilter(upper, lower);
+ }
+
+ if (upper != NULL) upper->Release();
+ if (lower != NULL) lower->Release();
+}
+
+IDirect3DBaseTexture9 *TextureStorage9_2D::getBaseTexture() const
+{
+ return mTexture;
+}
+
+void TextureStorage9_2D::initializeRenderTarget()
+{
+ ASSERT(mRenderTarget == NULL);
+
+ if (mTexture != NULL && isRenderTarget())
+ {
+ IDirect3DSurface9 *surface = getSurfaceLevel(0, false);
+
+ mRenderTarget = new RenderTarget9(mRenderer, surface);
+ }
+}
+
+TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size)
+ : TextureStorage9(renderer, GetTextureUsage(Renderer9::makeRenderer9(renderer)->ConvertTextureInternalFormat(internalformat), usage, forceRenderable))
+{
+ mTexture = NULL;
+ for (int i = 0; i < 6; ++i)
+ {
+ mRenderTarget[i] = NULL;
+ }
+
+ // 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 (size > 0)
+ {
+ IDirect3DDevice9 *device = mRenderer->getDevice();
+ int height = size;
+ gl::MakeValidSize(false, gl::IsCompressed(internalformat), &size, &height, &mLodOffset);
+ HRESULT result = device->CreateCubeTexture(size, levels ? levels + mLodOffset : 0, getUsage(),
+ mRenderer->ConvertTextureInternalFormat(internalformat), getPool(), &mTexture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ gl::error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ initializeRenderTarget();
+}
+
+TextureStorage9_Cube::~TextureStorage9_Cube()
+{
+ if (mTexture)
+ {
+ mTexture->Release();
+ }
+
+ for (int i = 0; i < 6; ++i)
+ {
+ delete mRenderTarget[i];
+ }
+}
+
+TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage));
+ return static_cast<TextureStorage9_Cube*>(storage);
+}
+
+// Increments refcount on surface.
+// caller must Release() the returned surface
+IDirect3DSurface9 *TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty)
+{
+ IDirect3DSurface9 *surface = NULL;
+
+ if (mTexture)
+ {
+ D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget);
+ HRESULT result = mTexture->GetCubeMapSurface(face, level + mLodOffset, &surface);
+ ASSERT(SUCCEEDED(result));
+
+ // With managed textures the driver needs to be informed of updates to the lower mipmap levels
+ if (level != 0 && isManaged() && dirty)
+ {
+ mTexture->AddDirtyRect(face, NULL);
+ }
+ }
+
+ return surface;
+}
+
+RenderTarget *TextureStorage9_Cube::getRenderTarget(GLenum faceTarget)
+{
+ return mRenderTarget[gl::TextureCubeMap::faceIndex(faceTarget)];
+}
+
+void TextureStorage9_Cube::generateMipmap(int face, int level)
+{
+ IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level - 1, false);
+ IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
+
+ if (upper != NULL && lower != NULL)
+ {
+ mRenderer->boxFilter(upper, lower);
+ }
+
+ if (upper != NULL) upper->Release();
+ if (lower != NULL) lower->Release();
+}
+
+IDirect3DBaseTexture9 *TextureStorage9_Cube::getBaseTexture() const
+{
+ return mTexture;
+}
+
+void TextureStorage9_Cube::initializeRenderTarget()
+{
+ if (mTexture != NULL && isRenderTarget())
+ {
+ IDirect3DSurface9 *surface = NULL;
+
+ for (int i = 0; i < 6; ++i)
+ {
+ ASSERT(mRenderTarget[i] == NULL);
+
+ surface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, false);
+
+ mRenderTarget[i] = new RenderTarget9(mRenderer, surface);
+ }
+ }
+}
+
+} \ No newline at end of file
diff --git a/src/libGLESv2/renderer/TextureStorage9.h b/src/libGLESv2/renderer/TextureStorage9.h
new file mode 100644
index 00000000..86f551a1
--- /dev/null
+++ b/src/libGLESv2/renderer/TextureStorage9.h
@@ -0,0 +1,109 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// TextureStorage9.h: Defines the abstract rx::TextureStorage9 class and its concrete derived
+// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the
+// D3D9 texture.
+
+#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_
+#define LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_
+
+#include "libGLESv2/renderer/TextureStorage.h"
+#include "common/debug.h"
+
+namespace rx
+{
+class Renderer9;
+class SwapChain9;
+class RenderTarget;
+class RenderTarget9;
+class Blit;
+
+class TextureStorage9 : public TextureStorage
+{
+ public:
+ TextureStorage9(Renderer *renderer, DWORD usage);
+ virtual ~TextureStorage9();
+
+ static TextureStorage9 *makeTextureStorage9(TextureStorage *storage);
+
+ static DWORD GetTextureUsage(D3DFORMAT d3dfmt, GLenum glusage, bool forceRenderable);
+ static bool IsTextureFormatRenderable(D3DFORMAT format);
+
+ D3DPOOL getPool() const;
+ DWORD getUsage() const;
+
+ virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0;
+ virtual RenderTarget *getRenderTarget() { return NULL; }
+ virtual RenderTarget *getRenderTarget(GLenum faceTarget) { return NULL; }
+ virtual void generateMipmap(int level) {};
+ virtual void generateMipmap(int face, int level) {};
+
+ virtual int getLodOffset() const;
+ virtual bool isRenderTarget() const;
+ virtual bool isManaged() const;
+ virtual int levelCount();
+
+ protected:
+ int mLodOffset;
+ Renderer9 *mRenderer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorage9);
+
+ const DWORD mD3DUsage;
+ const D3DPOOL mD3DPool;
+};
+
+class TextureStorage9_2D : public TextureStorage9
+{
+ public:
+ TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain);
+ TextureStorage9_2D(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, GLsizei width, GLsizei height);
+ virtual ~TextureStorage9_2D();
+
+ static TextureStorage9_2D *makeTextureStorage9_2D(TextureStorage *storage);
+
+ IDirect3DSurface9 *getSurfaceLevel(int level, bool dirty);
+ virtual RenderTarget *getRenderTarget();
+ virtual IDirect3DBaseTexture9 *getBaseTexture() const;
+ virtual void generateMipmap(int level);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorage9_2D);
+
+ void initializeRenderTarget();
+
+ IDirect3DTexture9 *mTexture;
+ RenderTarget9 *mRenderTarget;
+};
+
+class TextureStorage9_Cube : public TextureStorage9
+{
+ public:
+ TextureStorage9_Cube(Renderer *renderer, int levels, GLenum internalformat, GLenum usage, bool forceRenderable, int size);
+ virtual ~TextureStorage9_Cube();
+
+ static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage);
+
+ IDirect3DSurface9 *getCubeMapSurface(GLenum faceTarget, int level, bool dirty);
+ virtual RenderTarget *getRenderTarget(GLenum faceTarget);
+ virtual IDirect3DBaseTexture9 *getBaseTexture() const;
+ virtual void generateMipmap(int face, int level);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureStorage9_Cube);
+
+ void initializeRenderTarget();
+
+ IDirect3DCubeTexture9 *mTexture;
+ RenderTarget9 *mRenderTarget[6];
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_
+
diff --git a/src/libGLESv2/renderer/VertexBuffer.cpp b/src/libGLESv2/renderer/VertexBuffer.cpp
new file mode 100644
index 00000000..a8589465
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexBuffer.cpp
@@ -0,0 +1,245 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface
+// class with derivations, classes that perform graphics API agnostic vertex buffer operations.
+
+#include "libGLESv2/renderer/VertexBuffer.h"
+#include "libGLESv2/renderer/Renderer.h"
+#include "libGLESv2/Context.h"
+
+namespace rx
+{
+
+unsigned int VertexBuffer::mNextSerial = 1;
+
+VertexBuffer::VertexBuffer()
+{
+ updateSerial();
+}
+
+VertexBuffer::~VertexBuffer()
+{
+}
+
+void VertexBuffer::updateSerial()
+{
+ mSerial = mNextSerial++;
+}
+
+unsigned int VertexBuffer::getSerial() const
+{
+ return mSerial;
+}
+
+VertexBufferInterface::VertexBufferInterface(rx::Renderer *renderer, bool dynamic) : mRenderer(renderer)
+{
+ mDynamic = dynamic;
+ mWritePosition = 0;
+ mReservedSpace = 0;
+
+ mVertexBuffer = renderer->createVertexBuffer();
+}
+
+VertexBufferInterface::~VertexBufferInterface()
+{
+ delete mVertexBuffer;
+}
+
+unsigned int VertexBufferInterface::getSerial() const
+{
+ return mVertexBuffer->getSerial();
+}
+
+unsigned int VertexBufferInterface::getBufferSize() const
+{
+ return mVertexBuffer->getBufferSize();
+}
+
+bool VertexBufferInterface::setBufferSize(unsigned int size)
+{
+ if (mVertexBuffer->getBufferSize() == 0)
+ {
+ return mVertexBuffer->initialize(size, mDynamic);
+ }
+ else
+ {
+ return mVertexBuffer->setBufferSize(size);
+ }
+}
+
+unsigned int VertexBufferInterface::getWritePosition() const
+{
+ return mWritePosition;
+}
+
+void VertexBufferInterface::setWritePosition(unsigned int writePosition)
+{
+ mWritePosition = writePosition;
+}
+
+bool VertexBufferInterface::discard()
+{
+ return mVertexBuffer->discard();
+}
+
+int VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances)
+{
+ if (!reserveSpace(mReservedSpace))
+ {
+ return -1;
+ }
+ mReservedSpace = 0;
+
+ if (!mVertexBuffer->storeVertexAttributes(attrib, start, count, instances, mWritePosition))
+ {
+ return -1;
+ }
+
+ int oldWritePos = static_cast<int>(mWritePosition);
+ mWritePosition += mVertexBuffer->getSpaceRequired(attrib, count, instances);
+
+ return oldWritePos;
+}
+
+int VertexBufferInterface::storeRawData(const void* data, unsigned int size)
+{
+ if (!reserveSpace(mReservedSpace))
+ {
+ return -1;
+ }
+ mReservedSpace = 0;
+
+ if (!mVertexBuffer->storeRawData(data, size, mWritePosition))
+ {
+ return -1;
+ }
+
+ int oldWritePos = static_cast<int>(mWritePosition);
+ mWritePosition += size;
+
+ return oldWritePos;
+}
+
+bool VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances)
+{
+ unsigned int requiredSpace = mVertexBuffer->getSpaceRequired(attribute, count, instances);
+
+ // Protect against integer overflow
+ if (mReservedSpace + requiredSpace < mReservedSpace)
+ {
+ return false;
+ }
+
+ mReservedSpace += requiredSpace;
+ return true;
+}
+
+bool VertexBufferInterface::reserveRawDataSpace(unsigned int size)
+{
+ // Protect against integer overflow
+ if (mReservedSpace + size < mReservedSpace)
+ {
+ return false;
+ }
+
+ mReservedSpace += size;
+ return true;
+}
+
+VertexBuffer* VertexBufferInterface::getVertexBuffer() const
+{
+ return mVertexBuffer;
+}
+
+
+StreamingVertexBufferInterface::StreamingVertexBufferInterface(rx::Renderer *renderer, std::size_t initialSize) : VertexBufferInterface(renderer, true)
+{
+ setBufferSize(initialSize);
+}
+
+StreamingVertexBufferInterface::~StreamingVertexBufferInterface()
+{
+}
+
+bool StreamingVertexBufferInterface::reserveSpace(unsigned int size)
+{
+ bool result = true;
+ unsigned int curBufferSize = getBufferSize();
+ if (size > curBufferSize)
+ {
+ result = setBufferSize(std::max(size, 3 * curBufferSize / 2));
+ setWritePosition(0);
+ }
+ else if (getWritePosition() + size > curBufferSize)
+ {
+ if (!discard())
+ {
+ return false;
+ }
+ setWritePosition(0);
+ }
+
+ return result;
+}
+
+StaticVertexBufferInterface::StaticVertexBufferInterface(rx::Renderer *renderer) : VertexBufferInterface(renderer, false)
+{
+}
+
+StaticVertexBufferInterface::~StaticVertexBufferInterface()
+{
+}
+
+int StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attribute)
+{
+ for (unsigned int element = 0; element < mCache.size(); element++)
+ {
+ if (mCache[element].type == attribute.mType &&
+ mCache[element].size == attribute.mSize &&
+ mCache[element].stride == attribute.stride() &&
+ mCache[element].normalized == attribute.mNormalized)
+ {
+ if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride())
+ {
+ return mCache[element].streamOffset;
+ }
+ }
+ }
+
+ return -1;
+}
+
+bool StaticVertexBufferInterface::reserveSpace(unsigned int size)
+{
+ unsigned int curSize = getBufferSize();
+ if (curSize == 0)
+ {
+ setBufferSize(size);
+ return true;
+ }
+ else if (curSize >= size)
+ {
+ return true;
+ }
+ else
+ {
+ UNREACHABLE(); // Static vertex buffers can't be resized
+ return false;
+ }
+}
+
+int StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances)
+{
+ int attributeOffset = attrib.mOffset % attrib.stride();
+ VertexElement element = { attrib.mType, attrib.mSize, attrib.stride(), attrib.mNormalized, attributeOffset, getWritePosition() };
+ mCache.push_back(element);
+
+ return VertexBufferInterface::storeVertexAttributes(attrib, start, count, instances);
+}
+
+}
diff --git a/src/libGLESv2/renderer/VertexBuffer.h b/src/libGLESv2/renderer/VertexBuffer.h
new file mode 100644
index 00000000..c474b05c
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexBuffer.h
@@ -0,0 +1,138 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexBuffer.h: Defines the abstract VertexBuffer class and VertexBufferInterface
+// class with derivations, classes that perform graphics API agnostic vertex buffer operations.
+
+#ifndef LIBGLESV2_RENDERER_VERTEXBUFFER_H_
+#define LIBGLESV2_RENDERER_VERTEXBUFFER_H_
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+class VertexAttribute;
+}
+
+namespace rx
+{
+class Renderer;
+
+class VertexBuffer
+{
+ public:
+ VertexBuffer();
+ virtual ~VertexBuffer();
+
+ virtual bool initialize(unsigned int size, bool dynamicUsage) = 0;
+
+ virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count,
+ GLsizei instances, unsigned int offset) = 0;
+ virtual bool storeRawData(const void* data, unsigned int size, unsigned int offset) = 0;
+
+ virtual unsigned int getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count,
+ GLsizei instances) const = 0;
+
+ virtual bool requiresConversion(const gl::VertexAttribute &attrib) const = 0;
+
+ virtual unsigned int getBufferSize() const = 0;
+ virtual bool setBufferSize(unsigned int size) = 0;
+ virtual bool discard() = 0;
+
+ unsigned int getSerial() const;
+
+ protected:
+ void updateSerial();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexBuffer);
+
+ unsigned int mSerial;
+ static unsigned int mNextSerial;
+};
+
+class VertexBufferInterface
+{
+ public:
+ VertexBufferInterface(rx::Renderer *renderer, bool dynamic);
+ virtual ~VertexBufferInterface();
+
+ bool reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances);
+ bool reserveRawDataSpace(unsigned int size);
+
+ unsigned int getBufferSize() const;
+
+ unsigned int getSerial() const;
+
+ virtual int storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances);
+ virtual int storeRawData(const void* data, unsigned int size);
+
+ VertexBuffer* getVertexBuffer() const;
+
+ protected:
+ virtual bool reserveSpace(unsigned int size) = 0;
+
+ unsigned int getWritePosition() const;
+ void setWritePosition(unsigned int writePosition);
+
+ bool discard();
+
+ bool setBufferSize(unsigned int size);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexBufferInterface);
+
+ rx::Renderer *const mRenderer;
+
+ VertexBuffer* mVertexBuffer;
+
+ unsigned int mWritePosition;
+ unsigned int mReservedSpace;
+ bool mDynamic;
+};
+
+class StreamingVertexBufferInterface : public VertexBufferInterface
+{
+ public:
+ StreamingVertexBufferInterface(rx::Renderer *renderer, std::size_t initialSize);
+ ~StreamingVertexBufferInterface();
+
+ protected:
+ bool reserveSpace(unsigned int size);
+};
+
+class StaticVertexBufferInterface : public VertexBufferInterface
+{
+ public:
+ explicit StaticVertexBufferInterface(rx::Renderer *renderer);
+ ~StaticVertexBufferInterface();
+
+ int storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances);
+
+ // Returns the offset into the vertex buffer, or -1 if not found
+ int lookupAttribute(const gl::VertexAttribute &attribute);
+
+ protected:
+ bool reserveSpace(unsigned int size);
+
+ private:
+ struct VertexElement
+ {
+ GLenum type;
+ GLint size;
+ GLsizei stride;
+ bool normalized;
+ int attributeOffset;
+
+ unsigned int streamOffset;
+ };
+
+ std::vector<VertexElement> mCache;
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_VERTEXBUFFER_H_ \ No newline at end of file
diff --git a/src/libGLESv2/renderer/VertexBuffer11.cpp b/src/libGLESv2/renderer/VertexBuffer11.cpp
new file mode 100644
index 00000000..92c8755e
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexBuffer11.cpp
@@ -0,0 +1,418 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation.
+
+#include "libGLESv2/renderer/VertexBuffer11.h"
+#include "libGLESv2/renderer/BufferStorage.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/renderer/Renderer11.h"
+#include "libGLESv2/Context.h"
+
+namespace rx
+{
+
+VertexBuffer11::VertexBuffer11(rx::Renderer11 *const renderer) : mRenderer(renderer)
+{
+ mBuffer = NULL;
+ mBufferSize = 0;
+ mDynamicUsage = false;
+}
+
+VertexBuffer11::~VertexBuffer11()
+{
+ if (mBuffer)
+ {
+ mBuffer->Release();
+ mBuffer = NULL;
+ }
+}
+
+bool VertexBuffer11::initialize(unsigned int size, bool dynamicUsage)
+{
+ if (mBuffer)
+ {
+ mBuffer->Release();
+ mBuffer = NULL;
+ }
+
+ updateSerial();
+
+ if (size > 0)
+ {
+ ID3D11Device* dxDevice = mRenderer->getDevice();
+
+ D3D11_BUFFER_DESC bufferDesc;
+ bufferDesc.ByteWidth = size;
+ bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
+ bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ bufferDesc.MiscFlags = 0;
+ bufferDesc.StructureByteStride = 0;
+
+ HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer);
+ if (FAILED(result))
+ {
+ return false;
+ }
+ }
+
+ mBufferSize = size;
+ mDynamicUsage = dynamicUsage;
+ return true;
+}
+
+VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer));
+ return static_cast<VertexBuffer11*>(vetexBuffer);
+}
+
+bool VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count,
+ GLsizei instances, unsigned int offset)
+{
+ if (mBuffer)
+ {
+ gl::Buffer *buffer = attrib.mBoundBuffer.get();
+
+ int inputStride = attrib.stride();
+ const VertexConverter &converter = getVertexConversion(attrib);
+
+ ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext();
+
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ ERR("Vertex buffer map failed with error 0x%08x", result);
+ return false;
+ }
+
+ char* output = reinterpret_cast<char*>(mappedResource.pData) + offset;
+
+ const char *input = NULL;
+ if (buffer)
+ {
+ BufferStorage *storage = buffer->getStorage();
+ input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.mOffset);
+ }
+ else
+ {
+ input = static_cast<const char*>(attrib.mPointer);
+ }
+
+ if (instances == 0 || attrib.mDivisor == 0)
+ {
+ input += inputStride * start;
+ }
+
+ converter.conversionFunc(input, inputStride, count, output);
+
+ dxContext->Unmap(mBuffer, 0);
+
+ return true;
+ }
+ else
+ {
+ ERR("Vertex buffer not initialized.");
+ return false;
+ }
+}
+
+bool VertexBuffer11::storeRawData(const void* data, unsigned int size, unsigned int offset)
+{
+ if (mBuffer)
+ {
+ ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext();
+
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ ERR("Vertex buffer map failed with error 0x%08x", result);
+ return false;
+ }
+
+ char* bufferData = static_cast<char*>(mappedResource.pData);
+ memcpy(bufferData + offset, data, size);
+
+ dxContext->Unmap(mBuffer, 0);
+
+ return true;
+ }
+ else
+ {
+ ERR("Vertex buffer not initialized.");
+ return false;
+ }
+}
+
+unsigned int VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count,
+ GLsizei instances) const
+{
+ unsigned int elementSize = getVertexConversion(attrib).outputElementSize;
+
+ if (instances == 0 || attrib.mDivisor == 0)
+ {
+ return elementSize * count;
+ }
+ else
+ {
+ return elementSize * ((instances + attrib.mDivisor - 1) / attrib.mDivisor);
+ }
+}
+
+bool VertexBuffer11::requiresConversion(const gl::VertexAttribute &attrib) const
+{
+ return !getVertexConversion(attrib).identity;
+}
+
+unsigned int VertexBuffer11::getBufferSize() const
+{
+ return mBufferSize;
+}
+
+bool VertexBuffer11::setBufferSize(unsigned int size)
+{
+ if (size > mBufferSize)
+ {
+ return initialize(size, mDynamicUsage);
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool VertexBuffer11::discard()
+{
+ if (mBuffer)
+ {
+ ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext();
+
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
+ if (FAILED(result))
+ {
+ ERR("Vertex buffer map failed with error 0x%08x", result);
+ return false;
+ }
+
+ dxContext->Unmap(mBuffer, 0);
+
+ return true;
+ }
+ else
+ {
+ ERR("Vertex buffer not initialized.");
+ return false;
+ }
+}
+
+unsigned int VertexBuffer11::getVertexSize(const gl::VertexAttribute &attrib) const
+{
+ return getVertexConversion(attrib).outputElementSize;
+}
+
+DXGI_FORMAT VertexBuffer11::getDXGIFormat(const gl::VertexAttribute &attrib) const
+{
+ return getVertexConversion(attrib).dxgiFormat;
+}
+
+ID3D11Buffer *VertexBuffer11::getBuffer() const
+{
+ return mBuffer;
+}
+
+template <typename T, unsigned int componentCount, bool widen, bool normalized>
+static void copyVertexData(const void *input, unsigned int stride, unsigned int count, void *output)
+{
+ unsigned int attribSize = sizeof(T) * componentCount;
+
+ if (attribSize == stride && !widen)
+ {
+ memcpy(output, input, count * attribSize);
+ }
+ else
+ {
+ unsigned int outputStride = widen ? 4 : componentCount;
+ T defaultVal = normalized ? std::numeric_limits<T>::max() : T(1);
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ const T *offsetInput = reinterpret_cast<const T*>(reinterpret_cast<const char*>(input) + i * stride);
+ T *offsetOutput = reinterpret_cast<T*>(output) + i * outputStride;
+
+ for (unsigned int j = 0; j < componentCount; j++)
+ {
+ offsetOutput[j] = offsetInput[j];
+ }
+
+ if (widen)
+ {
+ offsetOutput[3] = defaultVal;
+ }
+ }
+ }
+}
+
+template <unsigned int componentCount>
+static void copyFixedVertexData(const void* input, unsigned int stride, unsigned int count, void* output)
+{
+ static const float divisor = 1.0f / (1 << 16);
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ const GLfixed* offsetInput = reinterpret_cast<const GLfixed*>(reinterpret_cast<const char*>(input) + stride * i);
+ float* offsetOutput = reinterpret_cast<float*>(output) + i * componentCount;
+
+ for (unsigned int j = 0; j < componentCount; j++)
+ {
+ offsetOutput[j] = static_cast<float>(offsetInput[j]) * divisor;
+ }
+ }
+}
+
+template <typename T, unsigned int componentCount, bool normalized>
+static void copyToFloatVertexData(const void* input, unsigned int stride, unsigned int count, void* output)
+{
+ typedef std::numeric_limits<T> NL;
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ const T *offsetInput = reinterpret_cast<const T*>(reinterpret_cast<const char*>(input) + stride * i);
+ float *offsetOutput = reinterpret_cast<float*>(output) + i * componentCount;
+
+ for (unsigned int j = 0; j < componentCount; j++)
+ {
+ if (normalized)
+ {
+ if (NL::is_signed)
+ {
+ const float divisor = 1.0f / (2 * static_cast<float>(NL::max()) + 1);
+ offsetOutput[j] = (2 * static_cast<float>(offsetInput[j]) + 1) * divisor;
+ }
+ else
+ {
+ offsetOutput[j] = static_cast<float>(offsetInput[j]) / NL::max();
+ }
+ }
+ else
+ {
+ offsetOutput[j] = static_cast<float>(offsetInput[j]);
+ }
+ }
+ }
+}
+
+const VertexBuffer11::VertexConverter VertexBuffer11::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] =
+{
+ { // GL_BYTE
+ { // unnormalized
+ { &copyToFloatVertexData<GLbyte, 1, false>, false, DXGI_FORMAT_R32_FLOAT, 4 },
+ { &copyToFloatVertexData<GLbyte, 2, false>, false, DXGI_FORMAT_R32G32_FLOAT, 8 },
+ { &copyToFloatVertexData<GLbyte, 3, false>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 },
+ { &copyToFloatVertexData<GLbyte, 4, false>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 },
+ },
+ { // normalized
+ { &copyVertexData<GLbyte, 1, false, true>, true, DXGI_FORMAT_R8_SNORM, 1 },
+ { &copyVertexData<GLbyte, 2, false, true>, true, DXGI_FORMAT_R8G8_SNORM, 2 },
+ { &copyVertexData<GLbyte, 3, true, true>, false, DXGI_FORMAT_R8G8B8A8_SNORM, 4 },
+ { &copyVertexData<GLbyte, 4, false, true>, true, DXGI_FORMAT_R8G8B8A8_SNORM, 4 },
+ },
+ },
+ { // GL_UNSIGNED_BYTE
+ { // unnormalized
+ { &copyToFloatVertexData<GLubyte, 1, false>, false, DXGI_FORMAT_R32_FLOAT, 4 },
+ { &copyToFloatVertexData<GLubyte, 2, false>, false, DXGI_FORMAT_R32G32_FLOAT, 8 },
+ { &copyToFloatVertexData<GLubyte, 3, false>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 },
+ { &copyToFloatVertexData<GLubyte, 4, false>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 },
+ },
+ { // normalized
+ { &copyVertexData<GLubyte, 1, false, true>, true, DXGI_FORMAT_R8_UNORM, 1 },
+ { &copyVertexData<GLubyte, 2, false, true>, true, DXGI_FORMAT_R8G8_UNORM, 2 },
+ { &copyVertexData<GLubyte, 3, true, true>, false, DXGI_FORMAT_R8G8B8A8_UNORM, 4 },
+ { &copyVertexData<GLubyte, 4, false, true>, true, DXGI_FORMAT_R8G8B8A8_UNORM, 4 },
+ },
+ },
+ { // GL_SHORT
+ { // unnormalized
+ { &copyToFloatVertexData<GLshort, 1, false>, false, DXGI_FORMAT_R32_FLOAT, 4 },
+ { &copyToFloatVertexData<GLshort, 2, false>, false, DXGI_FORMAT_R32G32_FLOAT, 8 },
+ { &copyToFloatVertexData<GLshort, 3, false>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 },
+ { &copyToFloatVertexData<GLshort, 4, false>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 },
+ },
+ { // normalized
+ { &copyVertexData<GLshort, 1, false, true>, true, DXGI_FORMAT_R16_SNORM, 2 },
+ { &copyVertexData<GLshort, 2, false, true>, true, DXGI_FORMAT_R16G16_SNORM, 4 },
+ { &copyVertexData<GLshort, 3, true, true>, false, DXGI_FORMAT_R16G16B16A16_SNORM, 8 },
+ { &copyVertexData<GLshort, 4, false, true>, true, DXGI_FORMAT_R16G16B16A16_SNORM, 8 },
+ },
+ },
+ { // GL_UNSIGNED_SHORT
+ { // unnormalized
+ { &copyToFloatVertexData<GLushort, 1, false>, false, DXGI_FORMAT_R32_FLOAT, 4 },
+ { &copyToFloatVertexData<GLushort, 2, false>, false, DXGI_FORMAT_R32G32_FLOAT, 8 },
+ { &copyToFloatVertexData<GLushort, 3, false>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 },
+ { &copyToFloatVertexData<GLushort, 4, false>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 },
+ },
+ { // normalized
+ { &copyVertexData<GLushort, 1, false, true>, true, DXGI_FORMAT_R16_UNORM, 2 },
+ { &copyVertexData<GLushort, 2, false, true>, true, DXGI_FORMAT_R16G16_UNORM, 4 },
+ { &copyVertexData<GLushort, 3, true, true>, false, DXGI_FORMAT_R16G16B16A16_UNORM, 8 },
+ { &copyVertexData<GLushort, 4, false, true>, true, DXGI_FORMAT_R16G16B16A16_UNORM, 8 },
+ },
+ },
+ { // GL_FIXED
+ { // unnormalized
+ { &copyFixedVertexData<1>, false, DXGI_FORMAT_R32_FLOAT, 4 },
+ { &copyFixedVertexData<2>, false, DXGI_FORMAT_R32G32_FLOAT, 8 },
+ { &copyFixedVertexData<3>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 },
+ { &copyFixedVertexData<4>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 },
+ },
+ { // normalized
+ { &copyFixedVertexData<1>, false, DXGI_FORMAT_R32_FLOAT, 4 },
+ { &copyFixedVertexData<2>, false, DXGI_FORMAT_R32G32_FLOAT, 8 },
+ { &copyFixedVertexData<3>, false, DXGI_FORMAT_R32G32B32_FLOAT, 12 },
+ { &copyFixedVertexData<4>, false, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 },
+ },
+ },
+ { // GL_FLOAT
+ { // unnormalized
+ { &copyVertexData<GLfloat, 1, false, false>, true, DXGI_FORMAT_R32_FLOAT, 4 },
+ { &copyVertexData<GLfloat, 2, false, false>, true, DXGI_FORMAT_R32G32_FLOAT, 8 },
+ { &copyVertexData<GLfloat, 3, false, false>, true, DXGI_FORMAT_R32G32B32_FLOAT, 12 },
+ { &copyVertexData<GLfloat, 4, false, false>, true, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 },
+ },
+ { // normalized
+ { &copyVertexData<GLfloat, 1, false, false>, true, DXGI_FORMAT_R32_FLOAT, 4 },
+ { &copyVertexData<GLfloat, 2, false, false>, true, DXGI_FORMAT_R32G32_FLOAT, 8 },
+ { &copyVertexData<GLfloat, 3, false, false>, true, DXGI_FORMAT_R32G32B32_FLOAT, 12 },
+ { &copyVertexData<GLfloat, 4, false, false>, true, DXGI_FORMAT_R32G32B32A32_FLOAT, 16 },
+ },
+ },
+};
+
+const VertexBuffer11::VertexConverter &VertexBuffer11::getVertexConversion(const gl::VertexAttribute &attribute)
+{
+ unsigned int typeIndex = 0;
+ switch (attribute.mType)
+ {
+ case GL_BYTE: typeIndex = 0; break;
+ case GL_UNSIGNED_BYTE: typeIndex = 1; break;
+ case GL_SHORT: typeIndex = 2; break;
+ case GL_UNSIGNED_SHORT: typeIndex = 3; break;
+ case GL_FIXED: typeIndex = 4; break;
+ case GL_FLOAT: typeIndex = 5; break;
+ default: UNREACHABLE(); break;
+ }
+
+ return mPossibleTranslations[typeIndex][attribute.mNormalized ? 1 : 0][attribute.mSize - 1];
+}
+
+}
diff --git a/src/libGLESv2/renderer/VertexBuffer11.h b/src/libGLESv2/renderer/VertexBuffer11.h
new file mode 100644
index 00000000..75e02507
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexBuffer11.h
@@ -0,0 +1,73 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexBuffer11.h: Defines the D3D11 VertexBuffer implementation.
+
+#ifndef LIBGLESV2_RENDERER_VERTEXBUFFER11_H_
+#define LIBGLESV2_RENDERER_VERTEXBUFFER11_H_
+
+#include "libGLESv2/renderer/VertexBuffer.h"
+
+namespace rx
+{
+class Renderer11;
+
+class VertexBuffer11 : public VertexBuffer
+{
+ public:
+ explicit VertexBuffer11(rx::Renderer11 *const renderer);
+ virtual ~VertexBuffer11();
+
+ virtual bool initialize(unsigned int size, bool dynamicUsage);
+
+ static VertexBuffer11 *makeVertexBuffer11(VertexBuffer *vetexBuffer);
+
+ virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances,
+ unsigned int offset);
+ virtual bool storeRawData(const void* data, unsigned int size, unsigned int offset);
+
+ virtual unsigned int getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) const;
+
+ virtual bool requiresConversion(const gl::VertexAttribute &attrib) const;
+
+ virtual unsigned int getBufferSize() const;
+ virtual bool setBufferSize(unsigned int size);
+ virtual bool discard();
+
+ unsigned int getVertexSize(const gl::VertexAttribute &attrib) const;
+ DXGI_FORMAT getDXGIFormat(const gl::VertexAttribute &attrib) const;
+
+ ID3D11Buffer *getBuffer() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexBuffer11);
+
+ rx::Renderer11 *const mRenderer;
+
+ ID3D11Buffer *mBuffer;
+ unsigned int mBufferSize;
+ bool mDynamicUsage;
+
+ typedef void (*VertexConversionFunction)(const void *, unsigned int, unsigned int, void *);
+ struct VertexConverter
+ {
+ VertexConversionFunction conversionFunc;
+ bool identity;
+ DXGI_FORMAT dxgiFormat;
+ unsigned int outputElementSize;
+ };
+
+ enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 };
+
+ // This table is used to generate mAttributeTypes.
+ static const VertexConverter mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
+
+ static const VertexConverter &getVertexConversion(const gl::VertexAttribute &attribute);
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_VERTEXBUFFER11_H_ \ No newline at end of file
diff --git a/src/libGLESv2/renderer/VertexBuffer9.cpp b/src/libGLESv2/renderer/VertexBuffer9.cpp
new file mode 100644
index 00000000..76dc73e3
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexBuffer9.cpp
@@ -0,0 +1,486 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation.
+
+#include "libGLESv2/renderer/VertexBuffer9.h"
+#include "libGLESv2/renderer/vertexconversion.h"
+#include "libGLESv2/renderer/BufferStorage.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/renderer/Renderer9.h"
+
+#include "libGLESv2/Buffer.h"
+
+namespace rx
+{
+
+bool VertexBuffer9::mTranslationsInitialized = false;
+VertexBuffer9::FormatConverter VertexBuffer9::mFormatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4];
+
+VertexBuffer9::VertexBuffer9(rx::Renderer9 *const renderer) : mRenderer(renderer)
+{
+ mVertexBuffer = NULL;
+ mBufferSize = 0;
+ mDynamicUsage = false;
+
+ if (!mTranslationsInitialized)
+ {
+ initializeTranslations(renderer->getCapsDeclTypes());
+ mTranslationsInitialized = true;
+ }
+}
+
+VertexBuffer9::~VertexBuffer9()
+{
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Release();
+ mVertexBuffer = NULL;
+ }
+}
+
+bool VertexBuffer9::initialize(unsigned int size, bool dynamicUsage)
+{
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Release();
+ mVertexBuffer = NULL;
+ }
+
+ updateSerial();
+
+ if (size > 0)
+ {
+ DWORD flags = D3DUSAGE_WRITEONLY;
+ if (dynamicUsage)
+ {
+ flags |= D3DUSAGE_DYNAMIC;
+ }
+
+ HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", size);
+ return false;
+ }
+ }
+
+ mBufferSize = size;
+ mDynamicUsage = dynamicUsage;
+ return true;
+}
+
+VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer)
+{
+ ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer));
+ return static_cast<VertexBuffer9*>(vertexBuffer);
+}
+
+bool VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count,
+ GLsizei instances, unsigned int offset)
+{
+ if (mVertexBuffer)
+ {
+ gl::Buffer *buffer = attrib.mBoundBuffer.get();
+
+ int inputStride = attrib.stride();
+ int elementSize = attrib.typeSize();
+ const FormatConverter &converter = formatConverter(attrib);
+
+ DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0;
+
+ void *mapPtr = NULL;
+ HRESULT result = mVertexBuffer->Lock(offset, spaceRequired(attrib, count, instances), &mapPtr, lockFlags);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ return false;
+ }
+
+ const char *input = NULL;
+ if (buffer)
+ {
+ BufferStorage *storage = buffer->getStorage();
+ input = static_cast<const char*>(storage->getData()) + static_cast<int>(attrib.mOffset);
+ }
+ else
+ {
+ input = static_cast<const char*>(attrib.mPointer);
+ }
+
+ if (instances == 0 || attrib.mDivisor == 0)
+ {
+ input += inputStride * start;
+ }
+
+ if (converter.identity && inputStride == elementSize)
+ {
+ memcpy(mapPtr, input, count * inputStride);
+ }
+ else
+ {
+ converter.convertArray(input, inputStride, count, mapPtr);
+ }
+
+ mVertexBuffer->Unlock();
+
+ return true;
+ }
+ else
+ {
+ ERR("Vertex buffer not initialized.");
+ return false;
+ }
+}
+
+bool VertexBuffer9::storeRawData(const void* data, unsigned int size, unsigned int offset)
+{
+ if (mVertexBuffer)
+ {
+ DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0;
+
+ void *mapPtr = NULL;
+ HRESULT result = mVertexBuffer->Lock(offset, size, &mapPtr, lockFlags);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ return false;
+ }
+
+ memcpy(mapPtr, data, size);
+
+ mVertexBuffer->Unlock();
+
+ return true;
+ }
+ else
+ {
+ ERR("Vertex buffer not initialized.");
+ return false;
+ }
+}
+
+unsigned int VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) const
+{
+ return spaceRequired(attrib, count, instances);
+}
+
+bool VertexBuffer9::requiresConversion(const gl::VertexAttribute &attrib) const
+{
+ return formatConverter(attrib).identity;
+}
+
+unsigned int VertexBuffer9::getVertexSize(const gl::VertexAttribute &attrib) const
+{
+ return spaceRequired(attrib, 1, 0);
+}
+
+D3DDECLTYPE VertexBuffer9::getDeclType(const gl::VertexAttribute &attrib) const
+{
+ return formatConverter(attrib).d3dDeclType;
+}
+
+unsigned int VertexBuffer9::getBufferSize() const
+{
+ return mBufferSize;
+}
+
+bool VertexBuffer9::setBufferSize(unsigned int size)
+{
+ if (size > mBufferSize)
+ {
+ return initialize(size, mDynamicUsage);
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool VertexBuffer9::discard()
+{
+ if (mVertexBuffer)
+ {
+ void *dummy;
+ HRESULT result;
+
+ result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ if (FAILED(result))
+ {
+ ERR("Discard lock failed with error 0x%08x", result);
+ return false;
+ }
+
+ result = mVertexBuffer->Unlock();
+ if (FAILED(result))
+ {
+ ERR("Discard unlock failed with error 0x%08x", result);
+ return false;
+ }
+
+ return true;
+ }
+ else
+ {
+ ERR("Vertex buffer not initialized.");
+ return false;
+ }
+}
+
+IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const
+{
+ return mVertexBuffer;
+}
+
+// Mapping from OpenGL-ES vertex attrib type to D3D decl type:
+//
+// BYTE SHORT (Cast)
+// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
+// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast)
+// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize)
+// SHORT SHORT (Identity)
+// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize)
+// UNSIGNED_SHORT FLOAT (Cast)
+// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize)
+// FIXED (not in WebGL) FLOAT (FixedToFloat)
+// FLOAT FLOAT (Identity)
+
+// GLToCType maps from GL type (as GLenum) to the C typedef.
+template <GLenum GLType> struct GLToCType { };
+
+template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; };
+template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; };
+template <> struct GLToCType<GL_SHORT> { typedef GLshort type; };
+template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; };
+template <> struct GLToCType<GL_FIXED> { typedef GLuint type; };
+template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; };
+
+// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
+enum D3DVertexType
+{
+ D3DVT_FLOAT,
+ D3DVT_SHORT,
+ D3DVT_SHORT_NORM,
+ D3DVT_UBYTE,
+ D3DVT_UBYTE_NORM,
+ D3DVT_USHORT_NORM
+};
+
+// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
+template <unsigned int D3DType> struct D3DToCType { };
+
+template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
+template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
+template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
+template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
+
+// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
+template <unsigned int type, int size> struct WidenRule { };
+
+template <int size> struct WidenRule<D3DVT_FLOAT, size> : NoWiden<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT, size> : WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE, size> : WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : WidenToEven<size> { };
+
+// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
+template <unsigned int d3dtype, int size> struct VertexTypeFlags { };
+
+template <unsigned int _capflag, unsigned int _declflag>
+struct VertexTypeFlagsHelper
+{
+ enum { capflag = _capflag };
+ enum { declflag = _declflag };
+};
+
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
+
+
+// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
+template <GLenum GLtype, bool normalized> struct VertexTypeMapping { };
+
+template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
+struct VertexTypeMappingBase
+{
+ enum { preferred = Preferred };
+ enum { fallback = Fallback };
+};
+
+template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast
+template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize
+template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity
+template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat
+template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity
+
+
+// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
+// The conversion rules themselves are defined in vertexconversion.h.
+
+// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
+template <GLenum fromType, bool normalized, unsigned int toType>
+struct ConversionRule : Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type> { };
+
+// All conversions from normalized types to float use the Normalize operator.
+template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : Normalize<typename GLToCType<fromType>::type> { };
+
+// Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules.
+template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { };
+template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : FixedToFloat<GLint, 16> { };
+
+// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
+// whether it is normalized or not.
+template <class T, bool normalized> struct DefaultVertexValuesStage2 { };
+
+template <class T> struct DefaultVertexValuesStage2<T, true> : NormalizedDefaultValues<T> { };
+template <class T> struct DefaultVertexValuesStage2<T, false> : SimpleDefaultValues<T> { };
+
+// Work out the default value rule for a D3D type (expressed as the C type) and
+template <class T, bool normalized> struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized> { };
+template <bool normalized> struct DefaultVertexValues<float, normalized> : SimpleDefaultValues<float> { };
+
+// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
+// The fallback conversion produces an output that all D3D9 devices must support.
+template <class T> struct UsePreferred { enum { type = T::preferred }; };
+template <class T> struct UseFallback { enum { type = T::fallback }; };
+
+// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
+// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
+// and the D3DDECLTYPE member needed for the vertex declaration in declflag.
+template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
+struct Converter
+ : VertexDataConverter<typename GLToCType<fromType>::type,
+ WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
+ ConversionRule<fromType,
+ normalized,
+ PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
+ DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
+{
+private:
+ enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
+ enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
+
+public:
+ enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
+ enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
+};
+
+// Initialize a TranslationInfo
+#define TRANSLATION(type, norm, size, preferred) \
+ { \
+ Converter<type, norm, size, preferred>::identity, \
+ Converter<type, norm, size, preferred>::finalSize, \
+ Converter<type, norm, size, preferred>::convertArray, \
+ static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \
+ }
+
+#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \
+ { \
+ Converter<type, norm, size, UsePreferred>::capflag, \
+ TRANSLATION(type, norm, size, UsePreferred), \
+ TRANSLATION(type, norm, size, UseFallback) \
+ }
+
+#define TRANSLATIONS_FOR_TYPE(type) \
+ { \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \
+ }
+
+#define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \
+ { \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ }
+
+const VertexBuffer9::TranslationDescription VertexBuffer9::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
+{
+ TRANSLATIONS_FOR_TYPE(GL_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_SHORT),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
+ TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED),
+ TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT)
+};
+
+void VertexBuffer9::initializeTranslations(DWORD declTypes)
+{
+ for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
+ {
+ for (unsigned int j = 0; j < 2; j++)
+ {
+ for (unsigned int k = 0; k < 4; k++)
+ {
+ if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0)
+ {
+ mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion;
+ }
+ else
+ {
+ mFormatConverters[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion;
+ }
+ }
+ }
+ }
+}
+
+unsigned int VertexBuffer9::typeIndex(GLenum type)
+{
+ switch (type)
+ {
+ case GL_BYTE: return 0;
+ case GL_UNSIGNED_BYTE: return 1;
+ case GL_SHORT: return 2;
+ case GL_UNSIGNED_SHORT: return 3;
+ case GL_FIXED: return 4;
+ case GL_FLOAT: return 5;
+
+ default: UNREACHABLE(); return 5;
+ }
+}
+
+const VertexBuffer9::FormatConverter &VertexBuffer9::formatConverter(const gl::VertexAttribute &attribute)
+{
+ return mFormatConverters[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1];
+}
+
+unsigned int VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances)
+{
+ unsigned int elementSize = formatConverter(attrib).outputElementSize;
+
+ if (instances == 0 || attrib.mDivisor == 0)
+ {
+ return elementSize * count;
+ }
+ else
+ {
+ return elementSize * ((instances + attrib.mDivisor - 1) / attrib.mDivisor);
+ }
+}
+
+}
diff --git a/src/libGLESv2/renderer/VertexBuffer9.h b/src/libGLESv2/renderer/VertexBuffer9.h
new file mode 100644
index 00000000..f771635b
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexBuffer9.h
@@ -0,0 +1,90 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexBuffer9.h: Defines the D3D9 VertexBuffer implementation.
+
+#ifndef LIBGLESV2_RENDERER_VERTEXBUFFER9_H_
+#define LIBGLESV2_RENDERER_VERTEXBUFFER9_H_
+
+#include "libGLESv2/renderer/VertexBuffer.h"
+
+namespace rx
+{
+class Renderer9;
+
+class VertexBuffer9 : public VertexBuffer
+{
+ public:
+ explicit VertexBuffer9(rx::Renderer9 *const renderer);
+ virtual ~VertexBuffer9();
+
+ virtual bool initialize(unsigned int size, bool dynamicUsage);
+
+ static VertexBuffer9 *makeVertexBuffer9(VertexBuffer *vertexBuffer);
+
+ virtual bool storeVertexAttributes(const gl::VertexAttribute &attrib, GLint start, GLsizei count, GLsizei instances,
+ unsigned int offset);
+ virtual bool storeRawData(const void* data, unsigned int size, unsigned int offset);
+
+ virtual unsigned int getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) const;
+
+ virtual bool requiresConversion(const gl::VertexAttribute &attrib) const;
+
+ unsigned int getVertexSize(const gl::VertexAttribute &attrib) const;
+ D3DDECLTYPE getDeclType(const gl::VertexAttribute &attrib) const;
+
+ virtual unsigned int getBufferSize() const;
+ virtual bool setBufferSize(unsigned int size);
+ virtual bool discard();
+
+ IDirect3DVertexBuffer9 *getBuffer() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexBuffer9);
+
+ rx::Renderer9 *const mRenderer;
+
+ IDirect3DVertexBuffer9 *mVertexBuffer;
+ unsigned int mBufferSize;
+ bool mDynamicUsage;
+
+ // Attribute format conversion
+ enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 };
+
+ struct FormatConverter
+ {
+ bool identity;
+ std::size_t outputElementSize;
+ void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out);
+ D3DDECLTYPE d3dDeclType;
+ };
+
+ static bool mTranslationsInitialized;
+ static void initializeTranslations(DWORD declTypes);
+
+ // [GL types as enumerated by typeIndex()][normalized][size - 1]
+ static FormatConverter mFormatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4];
+
+ struct TranslationDescription
+ {
+ DWORD capsFlag;
+ FormatConverter preferredConversion;
+ FormatConverter fallbackConversion;
+ };
+
+ // This table is used to generate mFormatConverters.
+ // [GL types as enumerated by typeIndex()][normalized][size - 1]
+ static const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4];
+
+ static unsigned int typeIndex(GLenum type);
+ static const FormatConverter &formatConverter(const gl::VertexAttribute &attribute);
+
+ static unsigned int spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances);
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_VERTEXBUFFER9_H_
diff --git a/src/libGLESv2/renderer/VertexDataManager.cpp b/src/libGLESv2/renderer/VertexDataManager.cpp
new file mode 100644
index 00000000..fd869b10
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexDataManager.cpp
@@ -0,0 +1,267 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#include "libGLESv2/renderer/VertexDataManager.h"
+#include "libGLESv2/renderer/BufferStorage.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/renderer/VertexBuffer.h"
+
+namespace
+{
+ enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
+ // This has to be at least 4k or else it fails on ATI cards.
+ enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 };
+}
+
+namespace rx
+{
+
+static int elementsInBuffer(const gl::VertexAttribute &attribute, int size)
+{
+ int stride = attribute.stride();
+ return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride;
+}
+
+VertexDataManager::VertexDataManager(Renderer *renderer) : mRenderer(renderer)
+{
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mCurrentValue[i][0] = std::numeric_limits<float>::quiet_NaN();
+ mCurrentValue[i][1] = std::numeric_limits<float>::quiet_NaN();
+ mCurrentValue[i][2] = std::numeric_limits<float>::quiet_NaN();
+ mCurrentValue[i][3] = std::numeric_limits<float>::quiet_NaN();
+ mCurrentValueBuffer[i] = NULL;
+ mCurrentValueOffsets[i] = 0;
+ }
+
+ mStreamingBuffer = new StreamingVertexBufferInterface(renderer, INITIAL_STREAM_BUFFER_SIZE);
+
+ if (!mStreamingBuffer)
+ {
+ ERR("Failed to allocate the streaming vertex buffer.");
+ }
+}
+
+VertexDataManager::~VertexDataManager()
+{
+ delete mStreamingBuffer;
+
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ delete mCurrentValueBuffer[i];
+ }
+}
+
+static bool directStoragePossible(VertexBufferInterface* vb, const gl::VertexAttribute& attrib)
+{
+ gl::Buffer *buffer = attrib.mBoundBuffer.get();
+ BufferStorage *storage = buffer ? buffer->getStorage() : NULL;
+
+ const bool isAligned = (attrib.stride() % 4 == 0) && (attrib.mOffset % 4 == 0);
+
+ return storage && storage->supportsDirectBinding() && !vb->getVertexBuffer()->requiresConversion(attrib) && isAligned;
+}
+
+GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances)
+{
+ if (!mStreamingBuffer)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1);
+ }
+
+ // Invalidate static buffers that don't contain matching attributes
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active && attribs[i].mArrayEnabled)
+ {
+ gl::Buffer *buffer = attribs[i].mBoundBuffer.get();
+ StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
+
+ if (staticBuffer && staticBuffer->getBufferSize() > 0 && staticBuffer->lookupAttribute(attribs[i]) == -1 &&
+ !directStoragePossible(staticBuffer, attribs[i]))
+ {
+ buffer->invalidateStaticData();
+ }
+ }
+ }
+
+ // Reserve the required space in the buffers
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active && attribs[i].mArrayEnabled)
+ {
+ gl::Buffer *buffer = attribs[i].mBoundBuffer.get();
+ StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
+ VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer);
+
+ if (!directStoragePossible(vertexBuffer, attribs[i]))
+ {
+ if (staticBuffer)
+ {
+ if (staticBuffer->getBufferSize() == 0)
+ {
+ int totalCount = elementsInBuffer(attribs[i], buffer->size());
+ if (!staticBuffer->reserveVertexSpace(attribs[i], totalCount, 0))
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+ }
+ }
+ else
+ {
+ if (!mStreamingBuffer->reserveVertexSpace(attribs[i], count, instances))
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+ }
+ }
+ }
+ }
+
+ // Perform the vertex data translations
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active)
+ {
+ if (attribs[i].mArrayEnabled)
+ {
+ gl::Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (!buffer && attribs[i].mPointer == NULL)
+ {
+ // This is an application error that would normally result in a crash, but we catch it and return an error
+ ERR("An enabled vertex array has no buffer and no pointer.");
+ return GL_INVALID_OPERATION;
+ }
+
+ StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
+ VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer);
+
+ BufferStorage *storage = buffer ? buffer->getStorage() : NULL;
+ bool directStorage = directStoragePossible(vertexBuffer, attribs[i]);
+
+ std::size_t streamOffset = -1;
+ unsigned int outputElementSize = 0;
+
+ if (directStorage)
+ {
+ outputElementSize = attribs[i].stride();
+ streamOffset = attribs[i].mOffset + outputElementSize * start;
+ storage->markBufferUsage();
+ }
+ else if (staticBuffer)
+ {
+ streamOffset = staticBuffer->lookupAttribute(attribs[i]);
+ outputElementSize = staticBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0);
+
+ if (streamOffset == -1)
+ {
+ // Convert the entire buffer
+ int totalCount = elementsInBuffer(attribs[i], storage->getSize());
+ int startIndex = attribs[i].mOffset / attribs[i].stride();
+
+ streamOffset = staticBuffer->storeVertexAttributes(attribs[i], -startIndex, totalCount, 0);
+ }
+
+ if (streamOffset != -1)
+ {
+ streamOffset += (attribs[i].mOffset / attribs[i].stride()) * outputElementSize;
+
+ if (instances == 0 || attribs[i].mDivisor == 0)
+ {
+ streamOffset += start * outputElementSize;
+ }
+ }
+ }
+ else
+ {
+ outputElementSize = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0);
+ streamOffset = mStreamingBuffer->storeVertexAttributes(attribs[i], start, count, instances);
+ }
+
+ if (streamOffset == -1)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ translated[i].storage = directStorage ? storage : NULL;
+ translated[i].vertexBuffer = vertexBuffer->getVertexBuffer();
+ translated[i].serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial();
+ translated[i].divisor = attribs[i].mDivisor;
+
+ translated[i].attribute = &attribs[i];
+ translated[i].stride = outputElementSize;
+ translated[i].offset = streamOffset;
+ }
+ else
+ {
+ if (!mCurrentValueBuffer[i])
+ {
+ mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE);
+ }
+
+ StreamingVertexBufferInterface *buffer = mCurrentValueBuffer[i];
+
+ if (mCurrentValue[i][0] != attribs[i].mCurrentValue[0] ||
+ mCurrentValue[i][1] != attribs[i].mCurrentValue[1] ||
+ mCurrentValue[i][2] != attribs[i].mCurrentValue[2] ||
+ mCurrentValue[i][3] != attribs[i].mCurrentValue[3])
+ {
+ unsigned int requiredSpace = sizeof(float) * 4;
+ if (!buffer->reserveRawDataSpace(requiredSpace))
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+ int streamOffset = buffer->storeRawData(attribs[i].mCurrentValue, requiredSpace);
+ if (streamOffset == -1)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ mCurrentValueOffsets[i] = streamOffset;
+ }
+
+ translated[i].storage = NULL;
+ translated[i].vertexBuffer = mCurrentValueBuffer[i]->getVertexBuffer();
+ translated[i].serial = mCurrentValueBuffer[i]->getSerial();
+ translated[i].divisor = 0;
+
+ translated[i].attribute = &attribs[i];
+ translated[i].stride = 0;
+ translated[i].offset = mCurrentValueOffsets[i];
+ }
+ }
+ }
+
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active && attribs[i].mArrayEnabled)
+ {
+ gl::Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (buffer)
+ {
+ buffer->promoteStaticUsage(count * attribs[i].typeSize());
+ }
+ }
+ }
+
+ return GL_NO_ERROR;
+}
+
+}
diff --git a/src/libGLESv2/renderer/VertexDataManager.h b/src/libGLESv2/renderer/VertexDataManager.h
new file mode 100644
index 00000000..28387e6b
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexDataManager.h
@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#ifndef LIBGLESV2_RENDERER_VERTEXDATAMANAGER_H_
+#define LIBGLESV2_RENDERER_VERTEXDATAMANAGER_H_
+
+#include "libGLESv2/Constants.h"
+#include "common/angleutils.h"
+
+namespace gl
+{
+class VertexAttribute;
+class ProgramBinary;
+}
+
+namespace rx
+{
+class BufferStorage;
+class StreamingVertexBufferInterface;
+class VertexBuffer;
+class Renderer;
+
+struct TranslatedAttribute
+{
+ bool active;
+
+ const gl::VertexAttribute *attribute;
+ UINT offset;
+ UINT stride; // 0 means not to advance the read pointer at all
+
+ VertexBuffer *vertexBuffer;
+ BufferStorage *storage;
+ unsigned int serial;
+ unsigned int divisor;
+};
+
+class VertexDataManager
+{
+ public:
+ VertexDataManager(rx::Renderer *renderer);
+ virtual ~VertexDataManager();
+
+ GLenum prepareVertexData(const gl::VertexAttribute attribs[], gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instances);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexDataManager);
+
+ rx::Renderer *const mRenderer;
+
+ StreamingVertexBufferInterface *mStreamingBuffer;
+
+ float mCurrentValue[gl::MAX_VERTEX_ATTRIBS][4];
+ StreamingVertexBufferInterface *mCurrentValueBuffer[gl::MAX_VERTEX_ATTRIBS];
+ std::size_t mCurrentValueOffsets[gl::MAX_VERTEX_ATTRIBS];
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_VERTEXDATAMANAGER_H_
diff --git a/src/libGLESv2/renderer/VertexDeclarationCache.cpp b/src/libGLESv2/renderer/VertexDeclarationCache.cpp
new file mode 100644
index 00000000..9b83a647
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexDeclarationCache.cpp
@@ -0,0 +1,217 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations.
+
+#include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/renderer/VertexBuffer9.h"
+#include "libGLESv2/renderer/VertexDeclarationCache.h"
+
+namespace rx
+{
+
+VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
+{
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ mVertexDeclCache[i].vertexDeclaration = NULL;
+ mVertexDeclCache[i].lruCount = 0;
+ }
+
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mAppliedVBs[i].serial = 0;
+ }
+
+ mLastSetVDecl = NULL;
+ mInstancingEnabled = true;
+}
+
+VertexDeclarationCache::~VertexDeclarationCache()
+{
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ if (mVertexDeclCache[i].vertexDeclaration)
+ {
+ mVertexDeclCache[i].vertexDeclaration->Release();
+ }
+ }
+}
+
+GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw)
+{
+ *repeatDraw = 1;
+
+ int indexedAttribute = gl::MAX_VERTEX_ATTRIBS;
+ int instancedAttribute = gl::MAX_VERTEX_ATTRIBS;
+
+ if (instances > 0)
+ {
+ // Find an indexed attribute to be mapped to D3D stream 0
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (attributes[i].active)
+ {
+ if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0)
+ {
+ indexedAttribute = i;
+ }
+ else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0)
+ {
+ instancedAttribute = i;
+ }
+ if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS)
+ break; // Found both an indexed and instanced attribute
+ }
+ }
+
+ if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS)
+ {
+ return GL_INVALID_OPERATION;
+ }
+ }
+
+ D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1];
+ D3DVERTEXELEMENT9 *element = &elements[0];
+
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (attributes[i].active)
+ {
+ // Directly binding the storage buffer is not supported for d3d9
+ ASSERT(attributes[i].storage == NULL);
+
+ int stream = i;
+
+ if (instances > 0)
+ {
+ // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
+ if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
+ {
+ *repeatDraw = instances;
+ }
+ else
+ {
+ if (i == indexedAttribute)
+ {
+ stream = 0;
+ }
+ else if (i == 0)
+ {
+ stream = indexedAttribute;
+ }
+
+ UINT frequency = 1;
+
+ if (attributes[i].divisor == 0)
+ {
+ frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
+ }
+ else
+ {
+ frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
+ }
+
+ device->SetStreamSourceFreq(stream, frequency);
+ mInstancingEnabled = true;
+ }
+ }
+
+ VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer);
+
+ if (mAppliedVBs[stream].serial != attributes[i].serial ||
+ mAppliedVBs[stream].stride != attributes[i].stride ||
+ mAppliedVBs[stream].offset != attributes[i].offset)
+ {
+ device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride);
+ mAppliedVBs[stream].serial = attributes[i].serial;
+ mAppliedVBs[stream].stride = attributes[i].stride;
+ mAppliedVBs[stream].offset = attributes[i].offset;
+ }
+
+ element->Stream = stream;
+ element->Offset = 0;
+ element->Type = attributes[i].attribute->mArrayEnabled ? vertexBuffer->getDeclType(*attributes[i].attribute) : D3DDECLTYPE_FLOAT4;
+ element->Method = D3DDECLMETHOD_DEFAULT;
+ element->Usage = D3DDECLUSAGE_TEXCOORD;
+ element->UsageIndex = programBinary->getSemanticIndex(i);
+ element++;
+ }
+ }
+
+ if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS)
+ {
+ if (mInstancingEnabled)
+ {
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ device->SetStreamSourceFreq(i, 1);
+ }
+
+ mInstancingEnabled = false;
+ }
+ }
+
+ static const D3DVERTEXELEMENT9 end = D3DDECL_END();
+ *(element++) = end;
+
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
+ if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
+ {
+ entry->lruCount = ++mMaxLru;
+ if(entry->vertexDeclaration != mLastSetVDecl)
+ {
+ device->SetVertexDeclaration(entry->vertexDeclaration);
+ mLastSetVDecl = entry->vertexDeclaration;
+ }
+
+ return GL_NO_ERROR;
+ }
+ }
+
+ VertexDeclCacheEntry *lastCache = mVertexDeclCache;
+
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
+ {
+ lastCache = &mVertexDeclCache[i];
+ }
+ }
+
+ if (lastCache->vertexDeclaration != NULL)
+ {
+ lastCache->vertexDeclaration->Release();
+ lastCache->vertexDeclaration = NULL;
+ // mLastSetVDecl is set to the replacement, so we don't have to worry
+ // about it.
+ }
+
+ memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
+ device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
+ device->SetVertexDeclaration(lastCache->vertexDeclaration);
+ mLastSetVDecl = lastCache->vertexDeclaration;
+ lastCache->lruCount = ++mMaxLru;
+
+ return GL_NO_ERROR;
+}
+
+void VertexDeclarationCache::markStateDirty()
+{
+ for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
+ {
+ mAppliedVBs[i].serial = 0;
+ }
+
+ mLastSetVDecl = NULL;
+ mInstancingEnabled = true; // Forces it to be disabled when not used
+}
+
+}
diff --git a/src/libGLESv2/renderer/VertexDeclarationCache.h b/src/libGLESv2/renderer/VertexDeclarationCache.h
new file mode 100644
index 00000000..3fc024a9
--- /dev/null
+++ b/src/libGLESv2/renderer/VertexDeclarationCache.h
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexDeclarationCache.h: Defines a helper class to construct and cache vertex declarations.
+
+#ifndef LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_
+#define LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_
+
+#include "libGLESv2/renderer/VertexDataManager.h"
+
+namespace gl
+{
+class VertexDataManager;
+}
+
+namespace rx
+{
+
+class VertexDeclarationCache
+{
+ public:
+ VertexDeclarationCache();
+ ~VertexDeclarationCache();
+
+ GLenum applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw);
+
+ void markStateDirty();
+
+ private:
+ UINT mMaxLru;
+
+ enum { NUM_VERTEX_DECL_CACHE_ENTRIES = 32 };
+
+ struct VBData
+ {
+ unsigned int serial;
+ unsigned int stride;
+ unsigned int offset;
+ };
+
+ VBData mAppliedVBs[gl::MAX_VERTEX_ATTRIBS];
+ IDirect3DVertexDeclaration9 *mLastSetVDecl;
+ bool mInstancingEnabled;
+
+ struct VertexDeclCacheEntry
+ {
+ D3DVERTEXELEMENT9 cachedElements[gl::MAX_VERTEX_ATTRIBS + 1];
+ UINT lruCount;
+ IDirect3DVertexDeclaration9 *vertexDeclaration;
+ } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES];
+};
+
+}
+
+#endif // LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_
diff --git a/src/libGLESv2/renderer/generatemip.h b/src/libGLESv2/renderer/generatemip.h
new file mode 100644
index 00000000..8e197360
--- /dev/null
+++ b/src/libGLESv2/renderer/generatemip.h
@@ -0,0 +1,203 @@
+//
+// 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.
+//
+
+// generatemip.h: Defines the GenerateMip function, templated on the format
+// type of the image for which mip levels are being generated.
+
+#ifndef LIBGLESV2_RENDERER_GENERATEMIP_H_
+#define LIBGLESV2_RENDERER_GENERATEMIP_H_
+
+#include "libGLESv2/mathutil.h"
+
+namespace rx
+{
+struct L8
+{
+ unsigned char L;
+
+ static void average(L8 *dst, const L8 *src1, const L8 *src2)
+ {
+ dst->L = ((src1->L ^ src2->L) >> 1) + (src1->L & src2->L);
+ }
+};
+
+typedef L8 R8; // R8 type is functionally equivalent for mip purposes
+typedef L8 A8; // A8 type is functionally equivalent for mip purposes
+
+struct A8L8
+{
+ unsigned char L;
+ unsigned char A;
+
+ 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);
+ }
+};
+
+typedef A8L8 R8G8; // R8G8 type is functionally equivalent for mip purposes
+
+struct A8R8G8B8
+{
+ unsigned char B;
+ unsigned char G;
+ unsigned char R;
+ unsigned char A;
+
+ 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);
+ }
+};
+
+typedef A8R8G8B8 R8G8B8A8; // R8G8B8A8 type is functionally equivalent for mip purposes
+
+struct A16B16G16R16F
+{
+ unsigned short R;
+ unsigned short G;
+ unsigned short B;
+ unsigned short A;
+
+ static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2)
+ {
+ dst->R = gl::float32ToFloat16((gl::float16ToFloat32(src1->R) + gl::float16ToFloat32(src2->R)) * 0.5f);
+ dst->G = gl::float32ToFloat16((gl::float16ToFloat32(src1->G) + gl::float16ToFloat32(src2->G)) * 0.5f);
+ dst->B = gl::float32ToFloat16((gl::float16ToFloat32(src1->B) + gl::float16ToFloat32(src2->B)) * 0.5f);
+ dst->A = gl::float32ToFloat16((gl::float16ToFloat32(src1->A) + gl::float16ToFloat32(src2->A)) * 0.5f);
+ }
+};
+
+struct R16F
+{
+ unsigned short R;
+
+ static void average(R16F *dst, const R16F *src1, const R16F *src2)
+ {
+ dst->R = gl::float32ToFloat16((gl::float16ToFloat32(src1->R) + gl::float16ToFloat32(src2->R)) * 0.5f);
+ }
+};
+
+struct R16G16F
+{
+ unsigned short R;
+ unsigned short G;
+
+ static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2)
+ {
+ dst->R = gl::float32ToFloat16((gl::float16ToFloat32(src1->R) + gl::float16ToFloat32(src2->R)) * 0.5f);
+ dst->G = gl::float32ToFloat16((gl::float16ToFloat32(src1->G) + gl::float16ToFloat32(src2->G)) * 0.5f);
+ }
+};
+
+struct A32B32G32R32F
+{
+ float R;
+ float G;
+ float B;
+ float A;
+
+ static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2)
+ {
+ dst->R = (src1->R + src2->R) * 0.5f;
+ dst->G = (src1->G + src2->G) * 0.5f;
+ dst->B = (src1->B + src2->B) * 0.5f;
+ dst->A = (src1->A + src2->A) * 0.5f;
+ }
+};
+
+struct R32F
+{
+ float R;
+
+ static void average(R32F *dst, const R32F *src1, const R32F *src2)
+ {
+ dst->R = (src1->R + src2->R) * 0.5f;
+ }
+};
+
+struct R32G32F
+{
+ float R;
+ float G;
+
+ static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2)
+ {
+ dst->R = (src1->R + src2->R) * 0.5f;
+ dst->G = (src1->G + src2->G) * 0.5f;
+ }
+};
+
+struct R32G32B32F
+{
+ float R;
+ float G;
+ float B;
+
+ static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2)
+ {
+ dst->R = (src1->R + src2->R) * 0.5f;
+ dst->G = (src1->G + src2->G) * 0.5f;
+ dst->B = (src1->B + src2->B) * 0.5f;
+ }
+};
+
+template <typename T>
+static void GenerateMip(unsigned int sourceWidth, unsigned int sourceHeight,
+ const unsigned char *sourceData, int sourcePitch,
+ unsigned char *destData, int destPitch)
+{
+ unsigned int mipWidth = std::max(1U, sourceWidth >> 1);
+ unsigned int mipHeight = std::max(1U, sourceHeight >> 1);
+
+ if (sourceHeight == 1)
+ {
+ ASSERT(sourceWidth != 1);
+
+ const T *src = (const T*)sourceData;
+ T *dst = (T*)destData;
+
+ for (unsigned int x = 0; x < mipWidth; x++)
+ {
+ T::average(&dst[x], &src[x * 2], &src[x * 2 + 1]);
+ }
+ }
+ else if (sourceWidth == 1)
+ {
+ ASSERT(sourceHeight != 1);
+
+ for (unsigned int y = 0; y < mipHeight; y++)
+ {
+ const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
+ const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
+ T *dst = (T*)(destData + y * destPitch);
+
+ T::average(dst, src0, src1);
+ }
+ }
+ else
+ {
+ for (unsigned int y = 0; y < mipHeight; y++)
+ {
+ const T *src0 = (const T*)(sourceData + y * 2 * sourcePitch);
+ const T *src1 = (const T*)(sourceData + y * 2 * sourcePitch + sourcePitch);
+ T *dst = (T*)(destData + y * destPitch);
+
+ for (unsigned int x = 0; x < mipWidth; x++)
+ {
+ T tmp0;
+ T tmp1;
+
+ T::average(&tmp0, &src0[x * 2], &src0[x * 2 + 1]);
+ T::average(&tmp1, &src1[x * 2], &src1[x * 2 + 1]);
+ T::average(&dst[x], &tmp0, &tmp1);
+ }
+ }
+ }
+}
+}
+
+#endif // LIBGLESV2_RENDERER_GENERATEMIP_H_
diff --git a/src/libGLESv2/renderer/renderer11_utils.cpp b/src/libGLESv2/renderer/renderer11_utils.cpp
new file mode 100644
index 00000000..13800da2
--- /dev/null
+++ b/src/libGLESv2/renderer/renderer11_utils.cpp
@@ -0,0 +1,688 @@
+#include "precompiled.h"
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// renderer11_utils.cpp: Conversion functions and other utility routines
+// specific to the D3D11 renderer.
+
+#include "libGLESv2/renderer/renderer11_utils.h"
+
+#include "common/debug.h"
+
+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;
+ default: UNREACHABLE();
+ }
+
+ return d3dBlendOp;
+}
+
+UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha)
+{
+ UINT8 mask = 0;
+ if (red)
+ {
+ mask |= D3D11_COLOR_WRITE_ENABLE_RED;
+ }
+ if (green)
+ {
+ mask |= D3D11_COLOR_WRITE_ENABLE_GREEN;
+ }
+ if (blue)
+ {
+ mask |= D3D11_COLOR_WRITE_ENABLE_BLUE;
+ }
+ if (alpha)
+ {
+ mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
+ }
+ return mask;
+}
+
+D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode)
+{
+ D3D11_CULL_MODE cull = D3D11_CULL_NONE;
+
+ if (cullEnabled)
+ {
+ switch (cullMode)
+ {
+ case GL_FRONT: cull = D3D11_CULL_FRONT; break;
+ case GL_BACK: cull = D3D11_CULL_BACK; break;
+ case GL_FRONT_AND_BACK: cull = D3D11_CULL_NONE; break;
+ default: UNREACHABLE();
+ }
+ }
+ else
+ {
+ cull = D3D11_CULL_NONE;
+ }
+
+ return cull;
+}
+
+D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison)
+{
+ D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER;
+ switch (comparison)
+ {
+ case GL_NEVER: d3dComp = D3D11_COMPARISON_NEVER; break;
+ case GL_ALWAYS: d3dComp = D3D11_COMPARISON_ALWAYS; break;
+ case GL_LESS: d3dComp = D3D11_COMPARISON_LESS; break;
+ case GL_LEQUAL: d3dComp = D3D11_COMPARISON_LESS_EQUAL; break;
+ case GL_EQUAL: d3dComp = D3D11_COMPARISON_EQUAL; break;
+ case GL_GREATER: d3dComp = D3D11_COMPARISON_GREATER; break;
+ case GL_GEQUAL: d3dComp = D3D11_COMPARISON_GREATER_EQUAL; break;
+ case GL_NOTEQUAL: d3dComp = D3D11_COMPARISON_NOT_EQUAL; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dComp;
+}
+
+D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled)
+{
+ return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
+}
+
+UINT8 ConvertStencilMask(GLuint stencilmask)
+{
+ return static_cast<UINT8>(stencilmask);
+}
+
+D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp)
+{
+ D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP;
+
+ switch (stencilOp)
+ {
+ case GL_ZERO: d3dStencilOp = D3D11_STENCIL_OP_ZERO; break;
+ case GL_KEEP: d3dStencilOp = D3D11_STENCIL_OP_KEEP; break;
+ case GL_REPLACE: d3dStencilOp = D3D11_STENCIL_OP_REPLACE; break;
+ case GL_INCR: d3dStencilOp = D3D11_STENCIL_OP_INCR_SAT; break;
+ case GL_DECR: d3dStencilOp = D3D11_STENCIL_OP_DECR_SAT; break;
+ case GL_INVERT: d3dStencilOp = D3D11_STENCIL_OP_INVERT; break;
+ case GL_INCR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_INCR; break;
+ case GL_DECR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_DECR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dStencilOp;
+}
+
+D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy)
+{
+ if (maxAnisotropy > 1.0f)
+ {
+ return D3D11_ENCODE_ANISOTROPIC_FILTER(false);
+ }
+ else
+ {
+ D3D11_FILTER_TYPE dxMin = D3D11_FILTER_TYPE_POINT;
+ D3D11_FILTER_TYPE dxMip = D3D11_FILTER_TYPE_POINT;
+ switch (minFilter)
+ {
+ case GL_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break;
+ case GL_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break;
+ case GL_NEAREST_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break;
+ case GL_LINEAR_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break;
+ case GL_NEAREST_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_LINEAR; break;
+ case GL_LINEAR_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_LINEAR; break;
+ default: UNREACHABLE();
+ }
+
+ D3D11_FILTER_TYPE dxMag = D3D11_FILTER_TYPE_POINT;
+ switch (magFilter)
+ {
+ case GL_NEAREST: dxMag = D3D11_FILTER_TYPE_POINT; break;
+ case GL_LINEAR: dxMag = D3D11_FILTER_TYPE_LINEAR; break;
+ default: UNREACHABLE();
+ }
+
+ return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, false);
+ }
+}
+
+D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap)
+{
+ switch (wrap)
+ {
+ case GL_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP;
+ case GL_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP;
+ case GL_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR;
+ default: UNREACHABLE();
+ }
+
+ return D3D11_TEXTURE_ADDRESS_WRAP;
+}
+
+FLOAT ConvertMinLOD(GLenum minFilter, unsigned int lodOffset)
+{
+ return (minFilter == GL_NEAREST || minFilter == GL_LINEAR) ? static_cast<float>(lodOffset) : -FLT_MAX;
+}
+
+FLOAT ConvertMaxLOD(GLenum minFilter, unsigned int lodOffset)
+{
+ return (minFilter == GL_NEAREST || minFilter == GL_LINEAR) ? static_cast<float>(lodOffset) : FLT_MAX;
+}
+
+}
+
+namespace d3d11_gl
+{
+
+GLenum ConvertBackBufferFormat(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM: return GL_RGBA8_OES;
+ case DXGI_FORMAT_B8G8R8A8_UNORM: return GL_BGRA8_EXT;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_RGBA8_OES;
+}
+
+GLenum ConvertDepthStencilFormat(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_UNKNOWN: return GL_NONE;
+ case DXGI_FORMAT_D16_UNORM: return GL_DEPTH_COMPONENT16;
+ case DXGI_FORMAT_D24_UNORM_S8_UINT: return GL_DEPTH24_STENCIL8_OES;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_DEPTH24_STENCIL8_OES;
+}
+
+GLenum ConvertRenderbufferFormat(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ return GL_BGRA8_EXT;
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ return GL_RGBA8_OES;
+ case DXGI_FORMAT_D16_UNORM:
+ return GL_DEPTH_COMPONENT16;
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ return GL_DEPTH24_STENCIL8_OES;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_RGBA8_OES;
+}
+
+GLenum ConvertTextureInternalFormat(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ return GL_RGBA8_OES;
+ case DXGI_FORMAT_A8_UNORM:
+ return GL_ALPHA8_EXT;
+ case DXGI_FORMAT_BC1_UNORM:
+ return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ case DXGI_FORMAT_BC2_UNORM:
+ return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE;
+ case DXGI_FORMAT_BC3_UNORM:
+ return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE;
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ return GL_RGBA32F_EXT;
+ case DXGI_FORMAT_R32G32B32_FLOAT:
+ return GL_RGB32F_EXT;
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ return GL_RGBA16F_EXT;
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ return GL_BGRA8_EXT;
+ case DXGI_FORMAT_R8_UNORM:
+ return GL_R8_EXT;
+ case DXGI_FORMAT_R8G8_UNORM:
+ return GL_RG8_EXT;
+ case DXGI_FORMAT_R16_FLOAT:
+ return GL_R16F_EXT;
+ case DXGI_FORMAT_R16G16_FLOAT:
+ return GL_RG16F_EXT;
+ case DXGI_FORMAT_D16_UNORM:
+ return GL_DEPTH_COMPONENT16;
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ return GL_DEPTH24_STENCIL8_OES;
+ case DXGI_FORMAT_UNKNOWN:
+ return GL_NONE;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_RGBA8_OES;
+}
+
+}
+
+namespace gl_d3d11
+{
+
+DXGI_FORMAT ConvertRenderbufferFormat(GLenum format)
+{
+ switch (format)
+ {
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGBA8_OES:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ return DXGI_FORMAT_R8G8B8A8_UNORM;
+ case GL_BGRA8_EXT:
+ return DXGI_FORMAT_B8G8R8A8_UNORM;
+ case GL_DEPTH_COMPONENT16:
+ return DXGI_FORMAT_D16_UNORM;
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES:
+ return DXGI_FORMAT_D24_UNORM_S8_UINT;
+ default:
+ UNREACHABLE();
+ }
+
+ return DXGI_FORMAT_R8G8B8A8_UNORM;
+}
+
+DXGI_FORMAT ConvertTextureFormat(GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_RGB565:
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ case GL_LUMINANCE8_EXT:
+ case GL_LUMINANCE8_ALPHA8_EXT:
+ return DXGI_FORMAT_R8G8B8A8_UNORM;
+ case GL_ALPHA8_EXT:
+ return DXGI_FORMAT_A8_UNORM;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ return DXGI_FORMAT_BC1_UNORM;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ return DXGI_FORMAT_BC2_UNORM;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ return DXGI_FORMAT_BC3_UNORM;
+ case GL_RGBA32F_EXT:
+ case GL_ALPHA32F_EXT:
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ return DXGI_FORMAT_R32G32B32A32_FLOAT;
+ case GL_RGB32F_EXT:
+ case GL_LUMINANCE32F_EXT:
+ return DXGI_FORMAT_R32G32B32A32_FLOAT;
+ case GL_RGBA16F_EXT:
+ case GL_ALPHA16F_EXT:
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ case GL_RGB16F_EXT:
+ case GL_LUMINANCE16F_EXT:
+ return DXGI_FORMAT_R16G16B16A16_FLOAT;
+ case GL_BGRA8_EXT:
+ return DXGI_FORMAT_B8G8R8A8_UNORM;
+ case GL_R8_EXT:
+ return DXGI_FORMAT_R8_UNORM;
+ case GL_RG8_EXT:
+ return DXGI_FORMAT_R8G8_UNORM;
+ case GL_R16F_EXT:
+ return DXGI_FORMAT_R16_FLOAT;
+ case GL_RG16F_EXT:
+ return DXGI_FORMAT_R16G16_FLOAT;
+ case GL_DEPTH_COMPONENT16:
+ return DXGI_FORMAT_D16_UNORM;
+ case GL_DEPTH_COMPONENT32_OES:
+ case GL_DEPTH24_STENCIL8_OES:
+ return DXGI_FORMAT_D24_UNORM_S8_UINT;
+ case GL_NONE:
+ return DXGI_FORMAT_UNKNOWN;
+ default:
+ UNREACHABLE();
+ }
+
+ return DXGI_FORMAT_R8G8B8A8_UNORM;
+}
+
+}
+
+namespace d3d11
+{
+
+void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v)
+{
+ vertex->x = x;
+ vertex->y = y;
+ vertex->u = u;
+ vertex->v = v;
+}
+
+void SetPositionDepthColorVertex(PositionDepthColorVertex* vertex, float x, float y, float z,
+ const gl::Color &color)
+{
+ vertex->x = x;
+ vertex->y = y;
+ vertex->z = z;
+ vertex->r = color.red;
+ vertex->g = color.green;
+ vertex->b = color.blue;
+ vertex->a = color.alpha;
+}
+
+size_t ComputePixelSizeBits(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_R1_UNORM:
+ return 1;
+
+ case DXGI_FORMAT_A8_UNORM:
+ case DXGI_FORMAT_R8_SINT:
+ case DXGI_FORMAT_R8_SNORM:
+ case DXGI_FORMAT_R8_TYPELESS:
+ case DXGI_FORMAT_R8_UINT:
+ case DXGI_FORMAT_R8_UNORM:
+ return 8;
+
+ case DXGI_FORMAT_B5G5R5A1_UNORM:
+ case DXGI_FORMAT_B5G6R5_UNORM:
+ case DXGI_FORMAT_D16_UNORM:
+ case DXGI_FORMAT_R16_FLOAT:
+ case DXGI_FORMAT_R16_SINT:
+ case DXGI_FORMAT_R16_SNORM:
+ case DXGI_FORMAT_R16_TYPELESS:
+ case DXGI_FORMAT_R16_UINT:
+ case DXGI_FORMAT_R16_UNORM:
+ case DXGI_FORMAT_R8G8_SINT:
+ case DXGI_FORMAT_R8G8_SNORM:
+ case DXGI_FORMAT_R8G8_TYPELESS:
+ case DXGI_FORMAT_R8G8_UINT:
+ case DXGI_FORMAT_R8G8_UNORM:
+ return 16;
+
+ case DXGI_FORMAT_B8G8R8X8_TYPELESS:
+ case DXGI_FORMAT_B8G8R8X8_UNORM:
+ case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ case DXGI_FORMAT_D32_FLOAT:
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
+ case DXGI_FORMAT_G8R8_G8B8_UNORM:
+ case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
+ case DXGI_FORMAT_R10G10B10A2_TYPELESS:
+ case DXGI_FORMAT_R10G10B10A2_UINT:
+ case DXGI_FORMAT_R10G10B10A2_UNORM:
+ case DXGI_FORMAT_R11G11B10_FLOAT:
+ case DXGI_FORMAT_R16G16_FLOAT:
+ case DXGI_FORMAT_R16G16_SINT:
+ case DXGI_FORMAT_R16G16_SNORM:
+ case DXGI_FORMAT_R16G16_TYPELESS:
+ case DXGI_FORMAT_R16G16_UINT:
+ case DXGI_FORMAT_R16G16_UNORM:
+ case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
+ case DXGI_FORMAT_R24G8_TYPELESS:
+ case DXGI_FORMAT_R32_FLOAT:
+ case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
+ case DXGI_FORMAT_R32_SINT:
+ case DXGI_FORMAT_R32_TYPELESS:
+ case DXGI_FORMAT_R32_UINT:
+ case DXGI_FORMAT_R8G8_B8G8_UNORM:
+ case DXGI_FORMAT_R8G8B8A8_SINT:
+ case DXGI_FORMAT_R8G8B8A8_SNORM:
+ case DXGI_FORMAT_R8G8B8A8_TYPELESS:
+ case DXGI_FORMAT_R8G8B8A8_UINT:
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ case DXGI_FORMAT_B8G8R8A8_TYPELESS:
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
+ case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
+ case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
+ case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
+ return 32;
+
+ case DXGI_FORMAT_R16G16B16A16_FLOAT:
+ case DXGI_FORMAT_R16G16B16A16_SINT:
+ case DXGI_FORMAT_R16G16B16A16_SNORM:
+ case DXGI_FORMAT_R16G16B16A16_TYPELESS:
+ case DXGI_FORMAT_R16G16B16A16_UINT:
+ case DXGI_FORMAT_R16G16B16A16_UNORM:
+ case DXGI_FORMAT_R32G32_FLOAT:
+ case DXGI_FORMAT_R32G32_SINT:
+ case DXGI_FORMAT_R32G32_TYPELESS:
+ case DXGI_FORMAT_R32G32_UINT:
+ case DXGI_FORMAT_R32G8X24_TYPELESS:
+ return 64;
+
+ case DXGI_FORMAT_R32G32B32_FLOAT:
+ case DXGI_FORMAT_R32G32B32_SINT:
+ case DXGI_FORMAT_R32G32B32_TYPELESS:
+ case DXGI_FORMAT_R32G32B32_UINT:
+ return 96;
+
+ case DXGI_FORMAT_R32G32B32A32_FLOAT:
+ case DXGI_FORMAT_R32G32B32A32_SINT:
+ case DXGI_FORMAT_R32G32B32A32_TYPELESS:
+ case DXGI_FORMAT_R32G32B32A32_UINT:
+ return 128;
+
+ case DXGI_FORMAT_BC1_TYPELESS:
+ case DXGI_FORMAT_BC1_UNORM:
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ case DXGI_FORMAT_BC4_SNORM:
+ case DXGI_FORMAT_BC4_TYPELESS:
+ case DXGI_FORMAT_BC4_UNORM:
+ return 4;
+
+ case DXGI_FORMAT_BC2_TYPELESS:
+ case DXGI_FORMAT_BC2_UNORM:
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ case DXGI_FORMAT_BC3_TYPELESS:
+ case DXGI_FORMAT_BC3_UNORM:
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ case DXGI_FORMAT_BC5_SNORM:
+ case DXGI_FORMAT_BC5_TYPELESS:
+ case DXGI_FORMAT_BC5_UNORM:
+ case DXGI_FORMAT_BC6H_SF16:
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ case DXGI_FORMAT_BC6H_UF16:
+ case DXGI_FORMAT_BC7_TYPELESS:
+ case DXGI_FORMAT_BC7_UNORM:
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ return 8;
+
+ default:
+ return 0;
+ }
+}
+
+size_t ComputeBlockSizeBits(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_BC1_TYPELESS:
+ case DXGI_FORMAT_BC1_UNORM:
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ case DXGI_FORMAT_BC4_SNORM:
+ case DXGI_FORMAT_BC4_TYPELESS:
+ case DXGI_FORMAT_BC4_UNORM:
+ case DXGI_FORMAT_BC2_TYPELESS:
+ case DXGI_FORMAT_BC2_UNORM:
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ case DXGI_FORMAT_BC3_TYPELESS:
+ case DXGI_FORMAT_BC3_UNORM:
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ case DXGI_FORMAT_BC5_SNORM:
+ case DXGI_FORMAT_BC5_TYPELESS:
+ case DXGI_FORMAT_BC5_UNORM:
+ case DXGI_FORMAT_BC6H_SF16:
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ case DXGI_FORMAT_BC6H_UF16:
+ case DXGI_FORMAT_BC7_TYPELESS:
+ case DXGI_FORMAT_BC7_UNORM:
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ return ComputePixelSizeBits(format) * 16;
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+bool IsCompressed(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_BC1_TYPELESS:
+ case DXGI_FORMAT_BC1_UNORM:
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ case DXGI_FORMAT_BC4_SNORM:
+ case DXGI_FORMAT_BC4_TYPELESS:
+ case DXGI_FORMAT_BC4_UNORM:
+ case DXGI_FORMAT_BC2_TYPELESS:
+ case DXGI_FORMAT_BC2_UNORM:
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ case DXGI_FORMAT_BC3_TYPELESS:
+ case DXGI_FORMAT_BC3_UNORM:
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ case DXGI_FORMAT_BC5_SNORM:
+ case DXGI_FORMAT_BC5_TYPELESS:
+ case DXGI_FORMAT_BC5_UNORM:
+ case DXGI_FORMAT_BC6H_SF16:
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ case DXGI_FORMAT_BC6H_UF16:
+ case DXGI_FORMAT_BC7_TYPELESS:
+ case DXGI_FORMAT_BC7_UNORM:
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ return true;
+ case DXGI_FORMAT_UNKNOWN:
+ UNREACHABLE();
+ return false;
+ default:
+ return false;
+ }
+}
+
+unsigned int GetTextureFormatDimensionAlignment(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_BC1_TYPELESS:
+ case DXGI_FORMAT_BC1_UNORM:
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ case DXGI_FORMAT_BC4_SNORM:
+ case DXGI_FORMAT_BC4_TYPELESS:
+ case DXGI_FORMAT_BC4_UNORM:
+ case DXGI_FORMAT_BC2_TYPELESS:
+ case DXGI_FORMAT_BC2_UNORM:
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ case DXGI_FORMAT_BC3_TYPELESS:
+ case DXGI_FORMAT_BC3_UNORM:
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ case DXGI_FORMAT_BC5_SNORM:
+ case DXGI_FORMAT_BC5_TYPELESS:
+ case DXGI_FORMAT_BC5_UNORM:
+ case DXGI_FORMAT_BC6H_SF16:
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ case DXGI_FORMAT_BC6H_UF16:
+ case DXGI_FORMAT_BC7_TYPELESS:
+ case DXGI_FORMAT_BC7_UNORM:
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ return 4;
+ case DXGI_FORMAT_UNKNOWN:
+ UNREACHABLE();
+ return 1;
+ default:
+ return 1;
+ }
+}
+
+bool IsDepthStencilFormat(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
+ case DXGI_FORMAT_D32_FLOAT:
+ case DXGI_FORMAT_D24_UNORM_S8_UINT:
+ case DXGI_FORMAT_D16_UNORM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+DXGI_FORMAT GetDepthTextureFormat(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return DXGI_FORMAT_R32G8X24_TYPELESS;
+ case DXGI_FORMAT_D32_FLOAT: return DXGI_FORMAT_R32_TYPELESS;
+ case DXGI_FORMAT_D24_UNORM_S8_UINT: return DXGI_FORMAT_R24G8_TYPELESS;
+ case DXGI_FORMAT_D16_UNORM: return DXGI_FORMAT_R16_TYPELESS;
+ default: UNREACHABLE(); return DXGI_FORMAT_UNKNOWN;
+ }
+}
+
+DXGI_FORMAT GetDepthShaderResourceFormat(DXGI_FORMAT format)
+{
+ switch (format)
+ {
+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
+ case DXGI_FORMAT_D32_FLOAT: return DXGI_FORMAT_R32_UINT;
+ case DXGI_FORMAT_D24_UNORM_S8_UINT: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
+ case DXGI_FORMAT_D16_UNORM: return DXGI_FORMAT_R16_UNORM;
+ default: UNREACHABLE(); return DXGI_FORMAT_UNKNOWN;
+ }
+}
+
+HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name)
+{
+#if defined(_DEBUG)
+ return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name);
+#else
+ return S_OK;
+#endif
+}
+
+}
diff --git a/src/libGLESv2/renderer/renderer11_utils.h b/src/libGLESv2/renderer/renderer11_utils.h
new file mode 100644
index 00000000..1bc48c1a
--- /dev/null
+++ b/src/libGLESv2/renderer/renderer11_utils.h
@@ -0,0 +1,95 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// renderer11_utils.h: Conversion functions and other utility routines
+// specific to the D3D11 renderer.
+
+#ifndef LIBGLESV2_RENDERER_RENDERER11_UTILS_H
+#define LIBGLESV2_RENDERER_RENDERER11_UTILS_H
+
+#include "libGLESv2/angletypes.h"
+
+namespace gl_d3d11
+{
+
+D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha);
+D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp);
+UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha);
+
+D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode);
+
+D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison);
+D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled);
+UINT8 ConvertStencilMask(GLuint stencilmask);
+D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp);
+
+D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy);
+D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap);
+FLOAT ConvertMinLOD(GLenum minFilter, unsigned int lodOffset);
+FLOAT ConvertMaxLOD(GLenum minFilter, unsigned int lodOffset);
+
+DXGI_FORMAT ConvertRenderbufferFormat(GLenum format);
+DXGI_FORMAT ConvertTextureFormat(GLenum format);
+}
+
+namespace d3d11_gl
+{
+
+GLenum ConvertBackBufferFormat(DXGI_FORMAT format);
+GLenum ConvertDepthStencilFormat(DXGI_FORMAT format);
+GLenum ConvertRenderbufferFormat(DXGI_FORMAT format);
+GLenum ConvertTextureInternalFormat(DXGI_FORMAT format);
+
+}
+
+namespace d3d11
+{
+
+struct PositionTexCoordVertex
+{
+ float x, y;
+ float u, v;
+};
+void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v);
+
+struct PositionDepthColorVertex
+{
+ float x, y, z;
+ float r, g, b, a;
+};
+void SetPositionDepthColorVertex(PositionDepthColorVertex* vertex, float x, float y, float z,
+ const gl::Color &color);
+
+size_t ComputePixelSizeBits(DXGI_FORMAT format);
+size_t ComputeBlockSizeBits(DXGI_FORMAT format);
+
+bool IsCompressed(DXGI_FORMAT format);
+unsigned int GetTextureFormatDimensionAlignment(DXGI_FORMAT format);
+
+bool IsDepthStencilFormat(DXGI_FORMAT format);
+DXGI_FORMAT GetDepthTextureFormat(DXGI_FORMAT format);
+DXGI_FORMAT GetDepthShaderResourceFormat(DXGI_FORMAT format);
+
+HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name);
+
+inline bool isDeviceLostError(HRESULT errorCode)
+{
+ switch (errorCode)
+ {
+ case DXGI_ERROR_DEVICE_HUNG:
+ case DXGI_ERROR_DEVICE_REMOVED:
+ case DXGI_ERROR_DEVICE_RESET:
+ case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
+ case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+}
+
+#endif // LIBGLESV2_RENDERER_RENDERER11_UTILS_H
diff --git a/src/libGLESv2/renderer/renderer9_utils.cpp b/src/libGLESv2/renderer/renderer9_utils.cpp
new file mode 100644
index 00000000..da75d465
--- /dev/null
+++ b/src/libGLESv2/renderer/renderer9_utils.cpp
@@ -0,0 +1,500 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// renderer9_utils.cpp: Conversion functions and other utility routines
+// specific to the D3D9 renderer.
+
+#include "libGLESv2/renderer/renderer9_utils.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/Context.h"
+
+#include "common/debug.h"
+
+namespace gl_d3d9
+{
+
+D3DCMPFUNC ConvertComparison(GLenum comparison)
+{
+ D3DCMPFUNC d3dComp = D3DCMP_ALWAYS;
+ switch (comparison)
+ {
+ case GL_NEVER: d3dComp = D3DCMP_NEVER; break;
+ case GL_ALWAYS: d3dComp = D3DCMP_ALWAYS; break;
+ case GL_LESS: d3dComp = D3DCMP_LESS; break;
+ case GL_LEQUAL: d3dComp = D3DCMP_LESSEQUAL; break;
+ case GL_EQUAL: d3dComp = D3DCMP_EQUAL; break;
+ case GL_GREATER: d3dComp = D3DCMP_GREATER; break;
+ case GL_GEQUAL: d3dComp = D3DCMP_GREATEREQUAL; break;
+ case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dComp;
+}
+
+D3DCOLOR ConvertColor(gl::Color color)
+{
+ return D3DCOLOR_RGBA(gl::unorm<8>(color.red),
+ gl::unorm<8>(color.green),
+ gl::unorm<8>(color.blue),
+ gl::unorm<8>(color.alpha));
+}
+
+D3DBLEND ConvertBlendFunc(GLenum blend)
+{
+ D3DBLEND d3dBlend = D3DBLEND_ZERO;
+
+ switch (blend)
+ {
+ case GL_ZERO: d3dBlend = D3DBLEND_ZERO; break;
+ case GL_ONE: d3dBlend = D3DBLEND_ONE; break;
+ case GL_SRC_COLOR: d3dBlend = D3DBLEND_SRCCOLOR; break;
+ case GL_ONE_MINUS_SRC_COLOR: d3dBlend = D3DBLEND_INVSRCCOLOR; break;
+ case GL_DST_COLOR: d3dBlend = D3DBLEND_DESTCOLOR; break;
+ case GL_ONE_MINUS_DST_COLOR: d3dBlend = D3DBLEND_INVDESTCOLOR; break;
+ case GL_SRC_ALPHA: d3dBlend = D3DBLEND_SRCALPHA; break;
+ case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3DBLEND_INVSRCALPHA; break;
+ case GL_DST_ALPHA: d3dBlend = D3DBLEND_DESTALPHA; break;
+ case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3DBLEND_INVDESTALPHA; break;
+ case GL_CONSTANT_COLOR: d3dBlend = D3DBLEND_BLENDFACTOR; break;
+ case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
+ case GL_CONSTANT_ALPHA: d3dBlend = D3DBLEND_BLENDFACTOR; break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
+ case GL_SRC_ALPHA_SATURATE: d3dBlend = D3DBLEND_SRCALPHASAT; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dBlend;
+}
+
+D3DBLENDOP ConvertBlendOp(GLenum blendOp)
+{
+ D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD;
+
+ switch (blendOp)
+ {
+ case GL_FUNC_ADD: d3dBlendOp = D3DBLENDOP_ADD; break;
+ case GL_FUNC_SUBTRACT: d3dBlendOp = D3DBLENDOP_SUBTRACT; break;
+ case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dBlendOp;
+}
+
+D3DSTENCILOP ConvertStencilOp(GLenum stencilOp)
+{
+ D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP;
+
+ switch (stencilOp)
+ {
+ case GL_ZERO: d3dStencilOp = D3DSTENCILOP_ZERO; break;
+ case GL_KEEP: d3dStencilOp = D3DSTENCILOP_KEEP; break;
+ case GL_REPLACE: d3dStencilOp = D3DSTENCILOP_REPLACE; break;
+ case GL_INCR: d3dStencilOp = D3DSTENCILOP_INCRSAT; break;
+ case GL_DECR: d3dStencilOp = D3DSTENCILOP_DECRSAT; break;
+ case GL_INVERT: d3dStencilOp = D3DSTENCILOP_INVERT; break;
+ case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR; break;
+ case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dStencilOp;
+}
+
+D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap)
+{
+ D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP;
+
+ switch (wrap)
+ {
+ case GL_REPEAT: d3dWrap = D3DTADDRESS_WRAP; break;
+ case GL_CLAMP_TO_EDGE: d3dWrap = D3DTADDRESS_CLAMP; break;
+ case GL_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dWrap;
+}
+
+D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace)
+{
+ D3DCULL cull = D3DCULL_CCW;
+ switch (cullFace)
+ {
+ case GL_FRONT:
+ cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW);
+ break;
+ case GL_BACK:
+ cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW);
+ break;
+ case GL_FRONT_AND_BACK:
+ cull = D3DCULL_NONE; // culling will be handled during draw
+ break;
+ default: UNREACHABLE();
+ }
+
+ return cull;
+}
+
+D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace)
+{
+ D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X;
+
+ switch (cubeFace)
+ {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ face = D3DCUBEMAP_FACE_POSITIVE_X;
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ face = D3DCUBEMAP_FACE_NEGATIVE_X;
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ face = D3DCUBEMAP_FACE_POSITIVE_Y;
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ face = D3DCUBEMAP_FACE_NEGATIVE_Y;
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ face = D3DCUBEMAP_FACE_POSITIVE_Z;
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ face = D3DCUBEMAP_FACE_NEGATIVE_Z;
+ break;
+ default: UNREACHABLE();
+ }
+
+ return face;
+}
+
+DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha)
+{
+ return (red ? D3DCOLORWRITEENABLE_RED : 0) |
+ (green ? D3DCOLORWRITEENABLE_GREEN : 0) |
+ (blue ? D3DCOLORWRITEENABLE_BLUE : 0) |
+ (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0);
+}
+
+D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy)
+{
+ if (maxAnisotropy > 1.0f)
+ {
+ return D3DTEXF_ANISOTROPIC;
+ }
+
+ D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT;
+ switch (magFilter)
+ {
+ case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT; break;
+ case GL_LINEAR: d3dMagFilter = D3DTEXF_LINEAR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dMagFilter;
+}
+
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy)
+{
+ switch (minFilter)
+ {
+ case GL_NEAREST:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_NONE;
+ break;
+ case GL_LINEAR:
+ *d3dMinFilter = D3DTEXF_LINEAR;
+ *d3dMipFilter = D3DTEXF_NONE;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_POINT;
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ *d3dMinFilter = D3DTEXF_LINEAR;
+ *d3dMipFilter = D3DTEXF_POINT;
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_LINEAR;
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ *d3dMinFilter = D3DTEXF_LINEAR;
+ *d3dMipFilter = D3DTEXF_LINEAR;
+ break;
+ default:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_NONE;
+ UNREACHABLE();
+ }
+
+ if (maxAnisotropy > 1.0f)
+ {
+ *d3dMinFilter = D3DTEXF_ANISOTROPIC;
+ }
+}
+
+D3DFORMAT ConvertRenderbufferFormat(GLenum format)
+{
+ switch (format)
+ {
+ case GL_NONE: return D3DFMT_NULL;
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGBA8_OES: return D3DFMT_A8R8G8B8;
+ case GL_RGB565: return D3DFMT_R5G6B5;
+ case GL_RGB8_OES: return D3DFMT_X8R8G8B8;
+ case GL_DEPTH_COMPONENT16:
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8;
+ default: UNREACHABLE(); return D3DFMT_A8R8G8B8;
+ }
+}
+
+D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples)
+{
+ if (samples <= 1)
+ return D3DMULTISAMPLE_NONE;
+ else
+ return (D3DMULTISAMPLE_TYPE)samples;
+}
+
+}
+
+namespace d3d9_gl
+{
+
+unsigned int GetStencilSize(D3DFORMAT stencilFormat)
+{
+ if (stencilFormat == D3DFMT_INTZ)
+ {
+ return 8;
+ }
+ switch(stencilFormat)
+ {
+ case D3DFMT_D24FS8:
+ case D3DFMT_D24S8:
+ return 8;
+ case D3DFMT_D24X4S4:
+ return 4;
+ case D3DFMT_D15S1:
+ return 1;
+ case D3DFMT_D16_LOCKABLE:
+ case D3DFMT_D32:
+ case D3DFMT_D24X8:
+ case D3DFMT_D32F_LOCKABLE:
+ case D3DFMT_D16:
+ return 0;
+ //case D3DFMT_D32_LOCKABLE: return 0; // DirectX 9Ex only
+ //case D3DFMT_S8_LOCKABLE: return 8; // DirectX 9Ex only
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetAlphaSize(D3DFORMAT colorFormat)
+{
+ switch (colorFormat)
+ {
+ case D3DFMT_A16B16G16R16F:
+ return 16;
+ case D3DFMT_A32B32G32R32F:
+ return 32;
+ case D3DFMT_A2R10G10B10:
+ return 2;
+ case D3DFMT_A8R8G8B8:
+ return 8;
+ case D3DFMT_A1R5G5B5:
+ return 1;
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_R5G6B5:
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type)
+{
+ if (type == D3DMULTISAMPLE_NONMASKABLE)
+ return 0;
+ else
+ return type;
+}
+
+bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format)
+{
+ switch (d3dformat)
+ {
+ case D3DFMT_L8:
+ return (format == GL_LUMINANCE);
+ case D3DFMT_A8L8:
+ return (format == GL_LUMINANCE_ALPHA);
+ case D3DFMT_DXT1:
+ return (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
+ case D3DFMT_DXT3:
+ return (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE);
+ case D3DFMT_DXT5:
+ return (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE);
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_A16B16G16R16F:
+ case D3DFMT_A32B32G32R32F:
+ return (format == GL_RGBA || format == GL_BGRA_EXT);
+ case D3DFMT_X8R8G8B8:
+ return (format == GL_RGB);
+ default:
+ if (d3dformat == D3DFMT_INTZ && gl::IsDepthTexture(format))
+ return true;
+ return false;
+ }
+}
+
+GLenum ConvertBackBufferFormat(D3DFORMAT format)
+{
+ switch (format)
+ {
+ case D3DFMT_A4R4G4B4: return GL_RGBA4;
+ case D3DFMT_A8R8G8B8: return GL_RGBA8_OES;
+ case D3DFMT_A1R5G5B5: return GL_RGB5_A1;
+ case D3DFMT_R5G6B5: return GL_RGB565;
+ case D3DFMT_X8R8G8B8: return GL_RGB8_OES;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_RGBA4;
+}
+
+GLenum ConvertDepthStencilFormat(D3DFORMAT format)
+{
+ if (format == D3DFMT_INTZ)
+ {
+ return GL_DEPTH24_STENCIL8_OES;
+ }
+ switch (format)
+ {
+ case D3DFMT_D16:
+ case D3DFMT_D24X8:
+ return GL_DEPTH_COMPONENT16;
+ case D3DFMT_D24S8:
+ return GL_DEPTH24_STENCIL8_OES;
+ case D3DFMT_UNKNOWN:
+ return GL_NONE;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_DEPTH24_STENCIL8_OES;
+}
+
+GLenum ConvertRenderTargetFormat(D3DFORMAT format)
+{
+ if (format == D3DFMT_INTZ)
+ {
+ return GL_DEPTH24_STENCIL8_OES;
+ }
+
+ switch (format)
+ {
+ case D3DFMT_A4R4G4B4: return GL_RGBA4;
+ case D3DFMT_A8R8G8B8: return GL_RGBA8_OES;
+ case D3DFMT_A1R5G5B5: return GL_RGB5_A1;
+ case D3DFMT_R5G6B5: return GL_RGB565;
+ case D3DFMT_X8R8G8B8: return GL_RGB8_OES;
+ case D3DFMT_D16:
+ case D3DFMT_D24X8:
+ return GL_DEPTH_COMPONENT16;
+ case D3DFMT_D24S8:
+ return GL_DEPTH24_STENCIL8_OES;
+ case D3DFMT_UNKNOWN:
+ return GL_NONE;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_RGBA4;
+}
+
+GLenum GetEquivalentFormat(D3DFORMAT format)
+{
+ if (format == D3DFMT_INTZ)
+ return GL_DEPTH24_STENCIL8_OES;
+ if (format == D3DFMT_NULL)
+ return GL_NONE;
+
+ switch (format)
+ {
+ case D3DFMT_A4R4G4B4: return GL_RGBA4;
+ case D3DFMT_A8R8G8B8: return GL_RGBA8_OES;
+ case D3DFMT_A1R5G5B5: return GL_RGB5_A1;
+ case D3DFMT_R5G6B5: return GL_RGB565;
+ case D3DFMT_X8R8G8B8: return GL_RGB8_OES;
+ case D3DFMT_D16: return GL_DEPTH_COMPONENT16;
+ case D3DFMT_D24S8: return GL_DEPTH24_STENCIL8_OES;
+ case D3DFMT_UNKNOWN: return GL_NONE;
+ case D3DFMT_DXT1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ case D3DFMT_DXT3: return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE;
+ case D3DFMT_DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE;
+ case D3DFMT_A32B32G32R32F: return GL_RGBA32F_EXT;
+ case D3DFMT_A16B16G16R16F: return GL_RGBA16F_EXT;
+ case D3DFMT_L8: return GL_LUMINANCE8_EXT;
+ case D3DFMT_A8L8: return GL_LUMINANCE8_ALPHA8_EXT;
+ default: UNREACHABLE();
+ return GL_NONE;
+ }
+}
+
+}
+
+namespace d3d9
+{
+
+bool IsCompressedFormat(D3DFORMAT surfaceFormat)
+{
+ switch(surfaceFormat)
+ {
+ case D3DFMT_DXT1:
+ case D3DFMT_DXT2:
+ case D3DFMT_DXT3:
+ case D3DFMT_DXT4:
+ case D3DFMT_DXT5:
+ return true;
+ default:
+ return false;
+ }
+}
+
+size_t ComputeRowSize(D3DFORMAT format, unsigned int width)
+{
+ if (format == D3DFMT_INTZ)
+ {
+ return 4 * width;
+ }
+ switch (format)
+ {
+ case D3DFMT_L8:
+ return 1 * width;
+ case D3DFMT_A8L8:
+ return 2 * width;
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A8R8G8B8:
+ return 4 * width;
+ case D3DFMT_A16B16G16R16F:
+ return 8 * width;
+ case D3DFMT_A32B32G32R32F:
+ return 16 * width;
+ case D3DFMT_DXT1:
+ return 8 * ((width + 3) / 4);
+ case D3DFMT_DXT3:
+ case D3DFMT_DXT5:
+ return 16 * ((width + 3) / 4);
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+}
diff --git a/src/libGLESv2/renderer/renderer9_utils.h b/src/libGLESv2/renderer/renderer9_utils.h
new file mode 100644
index 00000000..bf6cdf1e
--- /dev/null
+++ b/src/libGLESv2/renderer/renderer9_utils.h
@@ -0,0 +1,74 @@
+//
+// 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.
+//
+
+// renderer9_utils.h: Conversion functions and other utility routines
+// specific to the D3D9 renderer
+
+#ifndef LIBGLESV2_RENDERER_RENDERER9_UTILS_H
+#define LIBGLESV2_RENDERER_RENDERER9_UTILS_H
+
+#include "libGLESv2/utilities.h"
+
+const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z')));
+const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N','U','L','L')));
+
+namespace gl_d3d9
+{
+
+D3DCMPFUNC ConvertComparison(GLenum comparison);
+D3DCOLOR ConvertColor(gl::Color color);
+D3DBLEND ConvertBlendFunc(GLenum blend);
+D3DBLENDOP ConvertBlendOp(GLenum blendOp);
+D3DSTENCILOP ConvertStencilOp(GLenum stencilOp);
+D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap);
+D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace);
+D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace);
+DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha);
+D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy);
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy);
+D3DFORMAT ConvertRenderbufferFormat(GLenum format);
+D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples);
+
+}
+
+namespace d3d9_gl
+{
+
+GLuint GetAlphaSize(D3DFORMAT colorFormat);
+GLuint GetStencilSize(D3DFORMAT stencilFormat);
+
+GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type);
+
+bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format);
+GLenum ConvertBackBufferFormat(D3DFORMAT format);
+GLenum ConvertDepthStencilFormat(D3DFORMAT format);
+GLenum ConvertRenderTargetFormat(D3DFORMAT format);
+GLenum GetEquivalentFormat(D3DFORMAT format);
+
+}
+
+namespace d3d9
+{
+bool IsCompressedFormat(D3DFORMAT format);
+size_t ComputeRowSize(D3DFORMAT format, unsigned int width);
+
+inline bool isDeviceLostError(HRESULT errorCode)
+{
+ switch (errorCode)
+ {
+ case D3DERR_DRIVERINTERNALERROR:
+ case D3DERR_DEVICELOST:
+ case D3DERR_DEVICEHUNG:
+ case D3DERR_DEVICEREMOVED:
+ return true;
+ default:
+ return false;
+ }
+}
+
+}
+
+#endif // LIBGLESV2_RENDERER_RENDERER9_UTILS_H
diff --git a/src/libGLESv2/renderer/shaders/Blit.ps b/src/libGLESv2/renderer/shaders/Blit.ps
new file mode 100644
index 00000000..dcb3bd0e
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/Blit.ps
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+sampler2D tex : s0;
+
+uniform float4 mode : c0;
+
+// Passthrough Pixel Shader
+// Outputs texture 0 sampled at texcoord 0.
+float4 passthroughps(float4 texcoord : TEXCOORD0) : COLOR
+{
+ return tex2D(tex, texcoord.xy);
+};
+
+// Luminance Conversion Pixel Shader
+// Outputs sample(tex0, tc0).rrra.
+// For LA output (pass A) set C0.X = 1, C0.Y = 0.
+// For L output (A = 1) set C0.X = 0, C0.Y = 1.
+float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR
+{
+ float4 tmp = tex2D(tex, texcoord.xy);
+ tmp.w = tmp.w * mode.x + mode.y;
+ return tmp.xxxw;
+};
+
+// RGB/A Component Mask Pixel Shader
+// Outputs sample(tex0, tc0) with options to force RGB = 0 and/or A = 1.
+// To force RGB = 0, set C0.X = 0, otherwise C0.X = 1.
+// To force A = 1, set C0.Z = 0, C0.W = 1, otherwise C0.Z = 1, C0.W = 0.
+float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR
+{
+ float4 tmp = tex2D(tex, texcoord.xy);
+ tmp.xyz = tmp.xyz * mode.x;
+ tmp.w = tmp.w * mode.z + mode.w;
+ return tmp;
+};
diff --git a/src/libGLESv2/renderer/shaders/Blit.vs b/src/libGLESv2/renderer/shaders/Blit.vs
new file mode 100644
index 00000000..3a36980b
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/Blit.vs
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+struct VS_OUTPUT
+{
+ float4 position : POSITION;
+ float4 texcoord : TEXCOORD0;
+};
+
+uniform float4 halfPixelSize : c0;
+
+// Standard Vertex Shader
+// Input 0 is the homogenous position.
+// Outputs the homogenous position as-is.
+// Outputs a tex coord with (0,0) in the upper-left corner of the screen and (1,1) in the bottom right.
+// C0.X must be negative half-pixel width, C0.Y must be half-pixel height. C0.ZW must be 0.
+VS_OUTPUT standardvs(in float4 position : POSITION)
+{
+ VS_OUTPUT Out;
+
+ Out.position = position + halfPixelSize;
+ Out.texcoord = position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0);
+
+ return Out;
+};
+
+// Flip Y Vertex Shader
+// Input 0 is the homogenous position.
+// Outputs the homogenous position as-is.
+// Outputs a tex coord with (0,1) in the upper-left corner of the screen and (1,0) in the bottom right.
+// C0.XY must be the half-pixel width and height. C0.ZW must be 0.
+VS_OUTPUT flipyvs(in float4 position : POSITION)
+{
+ VS_OUTPUT Out;
+
+ Out.position = position + halfPixelSize;
+ Out.texcoord = position * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0);
+
+ return Out;
+};
diff --git a/src/libGLESv2/renderer/shaders/Clear11.hlsl b/src/libGLESv2/renderer/shaders/Clear11.hlsl
new file mode 100644
index 00000000..042ac699
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/Clear11.hlsl
@@ -0,0 +1,38 @@
+void VS_Clear( in float3 inPosition : POSITION, in float4 inColor : COLOR,
+ out float4 outPosition : SV_POSITION, out float4 outColor : COLOR)
+{
+ outPosition = float4(inPosition, 1.0f);
+ outColor = inColor;
+}
+
+// Assume we are in SM4+, which has 8 color outputs
+struct PS_OutputMultiple
+{
+ float4 color0 : SV_TARGET0;
+ float4 color1 : SV_TARGET1;
+ float4 color2 : SV_TARGET2;
+ float4 color3 : SV_TARGET3;
+ float4 color4 : SV_TARGET4;
+ float4 color5 : SV_TARGET5;
+ float4 color6 : SV_TARGET6;
+ float4 color7 : SV_TARGET7;
+};
+
+PS_OutputMultiple PS_ClearMultiple(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR)
+{
+ PS_OutputMultiple 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 PS_ClearSingle(in float4 inPosition : SV_Position, in float4 inColor : COLOR) : SV_Target0
+{
+ return inColor;
+}
diff --git a/src/libGLESv2/renderer/shaders/Passthrough11.hlsl b/src/libGLESv2/renderer/shaders/Passthrough11.hlsl
new file mode 100644
index 00000000..43b7801e
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/Passthrough11.hlsl
@@ -0,0 +1,29 @@
+Texture2D Texture : register(t0);
+SamplerState Sampler : register(s0);
+
+void VS_Passthrough( in float2 inPosition : POSITION, in float2 inTexCoord : TEXCOORD0,
+ out float4 outPosition : SV_POSITION, out float2 outTexCoord : TEXCOORD0)
+{
+ outPosition = float4(inPosition, 0.0f, 1.0f);
+ outTexCoord = inTexCoord;
+}
+
+float4 PS_PassthroughRGBA(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0
+{
+ return Texture.Sample(Sampler, inTexCoord).rgba;
+}
+
+float4 PS_PassthroughRGB(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0
+{
+ return float4(Texture.Sample(Sampler, inTexCoord).rgb, 1.0f);
+}
+
+float4 PS_PassthroughLum(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0
+{
+ return float4(Texture.Sample(Sampler, inTexCoord).rrr, 1.0f);
+}
+
+float4 PS_PassthroughLumAlpha(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0
+{
+ return Texture.Sample(Sampler, inTexCoord).rrra;
+}
diff --git a/src/libGLESv2/renderer/shaders/compiled/clear11vs.h b/src/libGLESv2/renderer/shaders/compiled/clear11vs.h
new file mode 100644
index 00000000..9f9c7017
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/clear11vs.h
@@ -0,0 +1,133 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+// fxc /E VS_Clear /T vs_4_0 /Fh compiled/clear11vs.h Clear11.hlsl
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// POSITION 0 xyz 0 NONE float xyz
+// COLOR 0 xyzw 1 NONE float xyzw
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_POSITION 0 xyzw 0 POS float xyzw
+// COLOR 0 xyzw 1 NONE float xyzw
+//
+vs_4_0
+dcl_input v0.xyz
+dcl_input v1.xyzw
+dcl_output_siv o0.xyzw, position
+dcl_output o1.xyzw
+mov o0.xyz, v0.xyzx
+mov o0.w, l(1.000000)
+mov o1.xyzw, v1.xyzw
+ret
+// Approximately 4 instruction slots used
+#endif
+
+const BYTE g_VS_Clear[] =
+{
+ 68, 88, 66, 67, 109, 138,
+ 105, 83, 86, 190, 83, 125,
+ 72, 102, 194, 136, 46, 69,
+ 17, 121, 1, 0, 0, 0,
+ 48, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 140, 0, 0, 0, 220, 0,
+ 0, 0, 48, 1, 0, 0,
+ 180, 1, 0, 0, 82, 68,
+ 69, 70, 80, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 28, 0, 0, 0, 0, 4,
+ 254, 255, 0, 1, 0, 0,
+ 28, 0, 0, 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, 57, 46, 50,
+ 57, 46, 57, 53, 50, 46,
+ 51, 49, 49, 49, 0, 171,
+ 171, 171, 73, 83, 71, 78,
+ 72, 0, 0, 0, 2, 0,
+ 0, 0, 8, 0, 0, 0,
+ 56, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 7, 7, 0, 0,
+ 65, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 15, 15, 0, 0,
+ 80, 79, 83, 73, 84, 73,
+ 79, 78, 0, 67, 79, 76,
+ 79, 82, 0, 171, 79, 83,
+ 71, 78, 76, 0, 0, 0,
+ 2, 0, 0, 0, 8, 0,
+ 0, 0, 56, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 15, 0,
+ 0, 0, 68, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 0,
+ 1, 0, 0, 0, 15, 0,
+ 0, 0, 83, 86, 95, 80,
+ 79, 83, 73, 84, 73, 79,
+ 78, 0, 67, 79, 76, 79,
+ 82, 0, 171, 171, 83, 72,
+ 68, 82, 124, 0, 0, 0,
+ 64, 0, 1, 0, 31, 0,
+ 0, 0, 95, 0, 0, 3,
+ 114, 16, 16, 0, 0, 0,
+ 0, 0, 95, 0, 0, 3,
+ 242, 16, 16, 0, 1, 0,
+ 0, 0, 103, 0, 0, 4,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 101, 0, 0, 3, 242, 32,
+ 16, 0, 1, 0, 0, 0,
+ 54, 0, 0, 5, 114, 32,
+ 16, 0, 0, 0, 0, 0,
+ 70, 18, 16, 0, 0, 0,
+ 0, 0, 54, 0, 0, 5,
+ 130, 32, 16, 0, 0, 0,
+ 0, 0, 1, 64, 0, 0,
+ 0, 0, 128, 63, 54, 0,
+ 0, 5, 242, 32, 16, 0,
+ 1, 0, 0, 0, 70, 30,
+ 16, 0, 1, 0, 0, 0,
+ 62, 0, 0, 1, 83, 84,
+ 65, 84, 116, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 4, 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,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 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,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/clearmultiple11ps.h b/src/libGLESv2/renderer/shaders/compiled/clearmultiple11ps.h
new file mode 100644
index 00000000..c70eebb8
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/clearmultiple11ps.h
@@ -0,0 +1,199 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+// fxc /E PS_ClearMultiple /T ps_4_0 /Fh compiled/clearmultiple11ps.h
+// Clear11.hlsl
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_POSITION 0 xyzw 0 POS float
+// COLOR 0 xyzw 1 NONE float xyzw
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_TARGET 0 xyzw 0 TARGET float xyzw
+// SV_TARGET 1 xyzw 1 TARGET float xyzw
+// SV_TARGET 2 xyzw 2 TARGET float xyzw
+// SV_TARGET 3 xyzw 3 TARGET float xyzw
+// SV_TARGET 4 xyzw 4 TARGET float xyzw
+// SV_TARGET 5 xyzw 5 TARGET float xyzw
+// SV_TARGET 6 xyzw 6 TARGET float xyzw
+// SV_TARGET 7 xyzw 7 TARGET float xyzw
+//
+ps_4_0
+dcl_input_ps linear v1.xyzw
+dcl_output o0.xyzw
+dcl_output o1.xyzw
+dcl_output o2.xyzw
+dcl_output o3.xyzw
+dcl_output o4.xyzw
+dcl_output o5.xyzw
+dcl_output o6.xyzw
+dcl_output o7.xyzw
+mov o0.xyzw, v1.xyzw
+mov o1.xyzw, v1.xyzw
+mov o2.xyzw, v1.xyzw
+mov o3.xyzw, v1.xyzw
+mov o4.xyzw, v1.xyzw
+mov o5.xyzw, v1.xyzw
+mov o6.xyzw, v1.xyzw
+mov o7.xyzw, v1.xyzw
+ret
+// Approximately 9 instruction slots used
+#endif
+
+const BYTE g_PS_ClearMultiple[] =
+{
+ 68, 88, 66, 67, 146, 246,
+ 236, 240, 50, 40, 87, 55,
+ 73, 140, 251, 200, 8, 22,
+ 173, 117, 1, 0, 0, 0,
+ 88, 3, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 140, 0, 0, 0, 224, 0,
+ 0, 0, 188, 1, 0, 0,
+ 220, 2, 0, 0, 82, 68,
+ 69, 70, 80, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 28, 0, 0, 0, 0, 4,
+ 255, 255, 0, 1, 0, 0,
+ 28, 0, 0, 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, 57, 46, 50,
+ 57, 46, 57, 53, 50, 46,
+ 51, 49, 49, 49, 0, 171,
+ 171, 171, 73, 83, 71, 78,
+ 76, 0, 0, 0, 2, 0,
+ 0, 0, 8, 0, 0, 0,
+ 56, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 15, 0, 0, 0,
+ 68, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 15, 15, 0, 0,
+ 83, 86, 95, 80, 79, 83,
+ 73, 84, 73, 79, 78, 0,
+ 67, 79, 76, 79, 82, 0,
+ 171, 171, 79, 83, 71, 78,
+ 212, 0, 0, 0, 8, 0,
+ 0, 0, 8, 0, 0, 0,
+ 200, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 15, 0, 0, 0,
+ 200, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 15, 0, 0, 0,
+ 200, 0, 0, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 2, 0,
+ 0, 0, 15, 0, 0, 0,
+ 200, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 3, 0,
+ 0, 0, 15, 0, 0, 0,
+ 200, 0, 0, 0, 4, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 4, 0,
+ 0, 0, 15, 0, 0, 0,
+ 200, 0, 0, 0, 5, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 5, 0,
+ 0, 0, 15, 0, 0, 0,
+ 200, 0, 0, 0, 6, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 6, 0,
+ 0, 0, 15, 0, 0, 0,
+ 200, 0, 0, 0, 7, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 7, 0,
+ 0, 0, 15, 0, 0, 0,
+ 83, 86, 95, 84, 65, 82,
+ 71, 69, 84, 0, 171, 171,
+ 83, 72, 68, 82, 24, 1,
+ 0, 0, 64, 0, 0, 0,
+ 70, 0, 0, 0, 98, 16,
+ 0, 3, 242, 16, 16, 0,
+ 1, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 0, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 1, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 2, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 3, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 4, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 5, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 6, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 7, 0, 0, 0, 54, 0,
+ 0, 5, 242, 32, 16, 0,
+ 0, 0, 0, 0, 70, 30,
+ 16, 0, 1, 0, 0, 0,
+ 54, 0, 0, 5, 242, 32,
+ 16, 0, 1, 0, 0, 0,
+ 70, 30, 16, 0, 1, 0,
+ 0, 0, 54, 0, 0, 5,
+ 242, 32, 16, 0, 2, 0,
+ 0, 0, 70, 30, 16, 0,
+ 1, 0, 0, 0, 54, 0,
+ 0, 5, 242, 32, 16, 0,
+ 3, 0, 0, 0, 70, 30,
+ 16, 0, 1, 0, 0, 0,
+ 54, 0, 0, 5, 242, 32,
+ 16, 0, 4, 0, 0, 0,
+ 70, 30, 16, 0, 1, 0,
+ 0, 0, 54, 0, 0, 5,
+ 242, 32, 16, 0, 5, 0,
+ 0, 0, 70, 30, 16, 0,
+ 1, 0, 0, 0, 54, 0,
+ 0, 5, 242, 32, 16, 0,
+ 6, 0, 0, 0, 70, 30,
+ 16, 0, 1, 0, 0, 0,
+ 54, 0, 0, 5, 242, 32,
+ 16, 0, 7, 0, 0, 0,
+ 70, 30, 16, 0, 1, 0,
+ 0, 0, 62, 0, 0, 1,
+ 83, 84, 65, 84, 116, 0,
+ 0, 0, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 9, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 8, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/clearsingle11ps.h b/src/libGLESv2/renderer/shaders/compiled/clearsingle11ps.h
new file mode 100644
index 00000000..20395e2a
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/clearsingle11ps.h
@@ -0,0 +1,113 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+// fxc /E PS_ClearSingle /T ps_4_0 /Fh compiled/clearsingle11ps.h
+// Clear11.hlsl
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position 0 xyzw 0 POS float
+// COLOR 0 xyzw 1 NONE float xyzw
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target 0 xyzw 0 TARGET float xyzw
+//
+ps_4_0
+dcl_input_ps linear v1.xyzw
+dcl_output o0.xyzw
+mov o0.xyzw, v1.xyzw
+ret
+// Approximately 2 instruction slots used
+#endif
+
+const BYTE g_PS_ClearSingle[] =
+{
+ 68, 88, 66, 67, 11, 49,
+ 220, 157, 35, 106, 175, 161,
+ 180, 178, 147, 150, 134, 162,
+ 222, 79, 1, 0, 0, 0,
+ 208, 1, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 140, 0, 0, 0, 224, 0,
+ 0, 0, 20, 1, 0, 0,
+ 84, 1, 0, 0, 82, 68,
+ 69, 70, 80, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 28, 0, 0, 0, 0, 4,
+ 255, 255, 0, 1, 0, 0,
+ 28, 0, 0, 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, 57, 46, 50,
+ 57, 46, 57, 53, 50, 46,
+ 51, 49, 49, 49, 0, 171,
+ 171, 171, 73, 83, 71, 78,
+ 76, 0, 0, 0, 2, 0,
+ 0, 0, 8, 0, 0, 0,
+ 56, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 15, 0, 0, 0,
+ 68, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 15, 15, 0, 0,
+ 83, 86, 95, 80, 111, 115,
+ 105, 116, 105, 111, 110, 0,
+ 67, 79, 76, 79, 82, 0,
+ 171, 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, 97, 114,
+ 103, 101, 116, 0, 171, 171,
+ 83, 72, 68, 82, 56, 0,
+ 0, 0, 64, 0, 0, 0,
+ 14, 0, 0, 0, 98, 16,
+ 0, 3, 242, 16, 16, 0,
+ 1, 0, 0, 0, 101, 0,
+ 0, 3, 242, 32, 16, 0,
+ 0, 0, 0, 0, 54, 0,
+ 0, 5, 242, 32, 16, 0,
+ 0, 0, 0, 0, 70, 30,
+ 16, 0, 1, 0, 0, 0,
+ 62, 0, 0, 1, 83, 84,
+ 65, 84, 116, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 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,
+ 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/componentmaskps.h b/src/libGLESv2/renderer/shaders/compiled/componentmaskps.h
new file mode 100644
index 00000000..2b8f04b4
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/componentmaskps.h
@@ -0,0 +1,81 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+// fxc /E componentmaskps /T ps_2_0 /Fh compiled/componentmaskps.h Blit.ps
+//
+//
+// Parameters:
+//
+// float4 mode;
+// sampler2D tex;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------ ----- ----
+// mode c0 1
+// tex s0 1
+//
+
+ ps_2_0
+ dcl t0.xy
+ dcl_2d s0
+ texld r0, t0, s0
+ mul r1.xyz, r0, c0.x
+ mad r1.w, r0.w, c0.z, c0.w
+ mov oC0, r1
+
+// approximately 4 instruction slots used (1 texture, 3 arithmetic)
+#endif
+
+const BYTE g_ps20_componentmaskps[] =
+{
+ 0, 2, 255, 255, 254, 255,
+ 43, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 119, 0,
+ 0, 0, 0, 2, 255, 255,
+ 2, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 112, 0, 0, 0, 68, 0,
+ 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 76, 0,
+ 0, 0, 0, 0, 0, 0,
+ 92, 0, 0, 0, 3, 0,
+ 0, 0, 1, 0, 0, 0,
+ 96, 0, 0, 0, 0, 0,
+ 0, 0, 109, 111, 100, 101,
+ 0, 171, 171, 171, 1, 0,
+ 3, 0, 1, 0, 4, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 116, 101, 120, 0,
+ 4, 0, 12, 0, 1, 0,
+ 1, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 112, 115,
+ 95, 50, 95, 48, 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, 57, 46,
+ 50, 57, 46, 57, 53, 50,
+ 46, 51, 49, 49, 49, 0,
+ 31, 0, 0, 2, 0, 0,
+ 0, 128, 0, 0, 3, 176,
+ 31, 0, 0, 2, 0, 0,
+ 0, 144, 0, 8, 15, 160,
+ 66, 0, 0, 3, 0, 0,
+ 15, 128, 0, 0, 228, 176,
+ 0, 8, 228, 160, 5, 0,
+ 0, 3, 1, 0, 7, 128,
+ 0, 0, 228, 128, 0, 0,
+ 0, 160, 4, 0, 0, 4,
+ 1, 0, 8, 128, 0, 0,
+ 255, 128, 0, 0, 170, 160,
+ 0, 0, 255, 160, 1, 0,
+ 0, 2, 0, 8, 15, 128,
+ 1, 0, 228, 128, 255, 255,
+ 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/flipyvs.h b/src/libGLESv2/renderer/shaders/compiled/flipyvs.h
new file mode 100644
index 00000000..ef121016
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/flipyvs.h
@@ -0,0 +1,69 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+// fxc /E flipyvs /T vs_2_0 /Fh compiled/flipyvs.h Blit.vs
+//
+//
+// Parameters:
+//
+// float4 halfPixelSize;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------- ----- ----
+// halfPixelSize c0 1
+//
+
+ vs_2_0
+ def c1, 0.5, 1, 0, 0
+ dcl_position v0
+ add oPos, v0, c0
+ mad oT0, v0, c1.xxyy, c1.xxzz
+
+// approximately 2 instruction slots used
+#endif
+
+const BYTE g_vs20_flipyvs[] =
+{
+ 0, 2, 254, 255, 254, 255,
+ 35, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 87, 0,
+ 0, 0, 0, 2, 254, 255,
+ 1, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 80, 0, 0, 0, 48, 0,
+ 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 64, 0,
+ 0, 0, 0, 0, 0, 0,
+ 104, 97, 108, 102, 80, 105,
+ 120, 101, 108, 83, 105, 122,
+ 101, 0, 171, 171, 1, 0,
+ 3, 0, 1, 0, 4, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 118, 115, 95, 50,
+ 95, 48, 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, 57, 46, 50, 57,
+ 46, 57, 53, 50, 46, 51,
+ 49, 49, 49, 0, 81, 0,
+ 0, 5, 1, 0, 15, 160,
+ 0, 0, 0, 63, 0, 0,
+ 128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 31, 0,
+ 0, 2, 0, 0, 0, 128,
+ 0, 0, 15, 144, 2, 0,
+ 0, 3, 0, 0, 15, 192,
+ 0, 0, 228, 144, 0, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 15, 224, 0, 0,
+ 228, 144, 1, 0, 80, 160,
+ 1, 0, 160, 160, 255, 255,
+ 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/luminanceps.h b/src/libGLESv2/renderer/shaders/compiled/luminanceps.h
new file mode 100644
index 00000000..44dc7498
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/luminanceps.h
@@ -0,0 +1,80 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+// fxc /E luminanceps /T ps_2_0 /Fh compiled/luminanceps.h Blit.ps
+//
+//
+// Parameters:
+//
+// float4 mode;
+// sampler2D tex;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------ ----- ----
+// mode c0 1
+// tex s0 1
+//
+
+ ps_2_0
+ dcl t0.xy
+ dcl_2d s0
+ texld r0, t0, s0
+ mad r1.w, r0.w, c0.x, c0.y
+ mov r1.xyz, r0.x
+ mov oC0, r1
+
+// approximately 4 instruction slots used (1 texture, 3 arithmetic)
+#endif
+
+const BYTE g_ps20_luminanceps[] =
+{
+ 0, 2, 255, 255, 254, 255,
+ 43, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 119, 0,
+ 0, 0, 0, 2, 255, 255,
+ 2, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 112, 0, 0, 0, 68, 0,
+ 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 76, 0,
+ 0, 0, 0, 0, 0, 0,
+ 92, 0, 0, 0, 3, 0,
+ 0, 0, 1, 0, 0, 0,
+ 96, 0, 0, 0, 0, 0,
+ 0, 0, 109, 111, 100, 101,
+ 0, 171, 171, 171, 1, 0,
+ 3, 0, 1, 0, 4, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 116, 101, 120, 0,
+ 4, 0, 12, 0, 1, 0,
+ 1, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 112, 115,
+ 95, 50, 95, 48, 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, 57, 46,
+ 50, 57, 46, 57, 53, 50,
+ 46, 51, 49, 49, 49, 0,
+ 31, 0, 0, 2, 0, 0,
+ 0, 128, 0, 0, 3, 176,
+ 31, 0, 0, 2, 0, 0,
+ 0, 144, 0, 8, 15, 160,
+ 66, 0, 0, 3, 0, 0,
+ 15, 128, 0, 0, 228, 176,
+ 0, 8, 228, 160, 4, 0,
+ 0, 4, 1, 0, 8, 128,
+ 0, 0, 255, 128, 0, 0,
+ 0, 160, 0, 0, 85, 160,
+ 1, 0, 0, 2, 1, 0,
+ 7, 128, 0, 0, 0, 128,
+ 1, 0, 0, 2, 0, 8,
+ 15, 128, 1, 0, 228, 128,
+ 255, 255, 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/passthrough11vs.h b/src/libGLESv2/renderer/shaders/compiled/passthrough11vs.h
new file mode 100644
index 00000000..b12fff9b
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/passthrough11vs.h
@@ -0,0 +1,137 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+// fxc /E VS_Passthrough /T vs_4_0 /Fh compiled/passthrough11vs.h
+// Passthrough11.hlsl
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// POSITION 0 xy 0 NONE float xy
+// TEXCOORD 0 xy 1 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_POSITION 0 xyzw 0 POS float xyzw
+// TEXCOORD 0 xy 1 NONE float xy
+//
+vs_4_0
+dcl_input v0.xy
+dcl_input v1.xy
+dcl_output_siv o0.xyzw, position
+dcl_output o1.xy
+mov o0.xy, v0.xyxx
+mov o0.zw, l(0,0,0,1.000000)
+mov o1.xy, v1.xyxx
+ret
+// Approximately 4 instruction slots used
+#endif
+
+const BYTE g_VS_Passthrough[] =
+{
+ 68, 88, 66, 67, 117, 74,
+ 34, 79, 174, 226, 170, 74,
+ 110, 16, 237, 14, 67, 185,
+ 119, 167, 1, 0, 0, 0,
+ 68, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 140, 0, 0, 0, 224, 0,
+ 0, 0, 56, 1, 0, 0,
+ 200, 1, 0, 0, 82, 68,
+ 69, 70, 80, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 28, 0, 0, 0, 0, 4,
+ 254, 255, 0, 1, 0, 0,
+ 28, 0, 0, 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, 57, 46, 50,
+ 57, 46, 57, 53, 50, 46,
+ 51, 49, 49, 49, 0, 171,
+ 171, 171, 73, 83, 71, 78,
+ 76, 0, 0, 0, 2, 0,
+ 0, 0, 8, 0, 0, 0,
+ 56, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 3, 3, 0, 0,
+ 65, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 3, 3, 0, 0,
+ 80, 79, 83, 73, 84, 73,
+ 79, 78, 0, 84, 69, 88,
+ 67, 79, 79, 82, 68, 0,
+ 171, 171, 79, 83, 71, 78,
+ 80, 0, 0, 0, 2, 0,
+ 0, 0, 8, 0, 0, 0,
+ 56, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0,
+ 0, 0, 15, 0, 0, 0,
+ 68, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 3, 12, 0, 0,
+ 83, 86, 95, 80, 79, 83,
+ 73, 84, 73, 79, 78, 0,
+ 84, 69, 88, 67, 79, 79,
+ 82, 68, 0, 171, 171, 171,
+ 83, 72, 68, 82, 136, 0,
+ 0, 0, 64, 0, 1, 0,
+ 34, 0, 0, 0, 95, 0,
+ 0, 3, 50, 16, 16, 0,
+ 0, 0, 0, 0, 95, 0,
+ 0, 3, 50, 16, 16, 0,
+ 1, 0, 0, 0, 103, 0,
+ 0, 4, 242, 32, 16, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 101, 0, 0, 3,
+ 50, 32, 16, 0, 1, 0,
+ 0, 0, 54, 0, 0, 5,
+ 50, 32, 16, 0, 0, 0,
+ 0, 0, 70, 16, 16, 0,
+ 0, 0, 0, 0, 54, 0,
+ 0, 8, 194, 32, 16, 0,
+ 0, 0, 0, 0, 2, 64,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 128, 63,
+ 54, 0, 0, 5, 50, 32,
+ 16, 0, 1, 0, 0, 0,
+ 70, 16, 16, 0, 1, 0,
+ 0, 0, 62, 0, 0, 1,
+ 83, 84, 65, 84, 116, 0,
+ 0, 0, 4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 4, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 3, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/passthroughlum11ps.h b/src/libGLESv2/renderer/shaders/compiled/passthroughlum11ps.h
new file mode 100644
index 00000000..0d5c8ebd
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/passthroughlum11ps.h
@@ -0,0 +1,155 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+// fxc /E PS_PassthroughLum /T ps_4_0 /Fh compiled/passthroughlum11ps.h
+// Passthrough11.hlsl
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim Slot Elements
+// ------------------------------ ---------- ------- ----------- ---- --------
+// Sampler sampler NA NA 0 1
+// Texture texture float4 2d 0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_POSITION 0 xyzw 0 POS float
+// TEXCOORD 0 xy 1 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_TARGET 0 xyzw 0 TARGET float xyzw
+//
+ps_4_0
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_input_ps linear v1.xy
+dcl_output o0.xyzw
+dcl_temps 1
+sample r0.xyzw, v1.xyxx, t0.xyzw, s0
+mov o0.xyz, r0.xxxx
+mov o0.w, l(1.000000)
+ret
+// Approximately 4 instruction slots used
+#endif
+
+const BYTE g_PS_PassthroughLum[] =
+{
+ 68, 88, 66, 67, 97, 41,
+ 37, 154, 0, 174, 137, 157,
+ 76, 219, 230, 26, 227, 174,
+ 187, 66, 1, 0, 0, 0,
+ 128, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 220, 0, 0, 0, 52, 1,
+ 0, 0, 104, 1, 0, 0,
+ 4, 2, 0, 0, 82, 68,
+ 69, 70, 160, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0,
+ 28, 0, 0, 0, 0, 4,
+ 255, 255, 0, 1, 0, 0,
+ 108, 0, 0, 0, 92, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 100, 0, 0, 0, 2, 0,
+ 0, 0, 5, 0, 0, 0,
+ 4, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 1, 0, 0, 0, 13, 0,
+ 0, 0, 83, 97, 109, 112,
+ 108, 101, 114, 0, 84, 101,
+ 120, 116, 117, 114, 101, 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, 57,
+ 46, 50, 57, 46, 57, 53,
+ 50, 46, 51, 49, 49, 49,
+ 0, 171, 171, 171, 73, 83,
+ 71, 78, 80, 0, 0, 0,
+ 2, 0, 0, 0, 8, 0,
+ 0, 0, 56, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 15, 0,
+ 0, 0, 68, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 0,
+ 1, 0, 0, 0, 3, 3,
+ 0, 0, 83, 86, 95, 80,
+ 79, 83, 73, 84, 73, 79,
+ 78, 0, 84, 69, 88, 67,
+ 79, 79, 82, 68, 0, 171,
+ 171, 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, 148, 0,
+ 0, 0, 64, 0, 0, 0,
+ 37, 0, 0, 0, 90, 0,
+ 0, 3, 0, 96, 16, 0,
+ 0, 0, 0, 0, 88, 24,
+ 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, 101, 0, 0, 3,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 104, 0, 0, 2,
+ 1, 0, 0, 0, 69, 0,
+ 0, 9, 242, 0, 16, 0,
+ 0, 0, 0, 0, 70, 16,
+ 16, 0, 1, 0, 0, 0,
+ 70, 126, 16, 0, 0, 0,
+ 0, 0, 0, 96, 16, 0,
+ 0, 0, 0, 0, 54, 0,
+ 0, 5, 114, 32, 16, 0,
+ 0, 0, 0, 0, 6, 0,
+ 16, 0, 0, 0, 0, 0,
+ 54, 0, 0, 5, 130, 32,
+ 16, 0, 0, 0, 0, 0,
+ 1, 64, 0, 0, 0, 0,
+ 128, 63, 62, 0, 0, 1,
+ 83, 84, 65, 84, 116, 0,
+ 0, 0, 4, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 2, 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, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/passthroughlumalpha11ps.h b/src/libGLESv2/renderer/shaders/compiled/passthroughlumalpha11ps.h
new file mode 100644
index 00000000..6f9c14d3
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/passthroughlumalpha11ps.h
@@ -0,0 +1,151 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+// fxc /E PS_PassthroughLumAlpha /T ps_4_0 /Fh
+// compiled/passthroughlumalpha11ps.h Passthrough11.hlsl
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim Slot Elements
+// ------------------------------ ---------- ------- ----------- ---- --------
+// Sampler sampler NA NA 0 1
+// Texture texture float4 2d 0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_POSITION 0 xyzw 0 POS float
+// TEXCOORD 0 xy 1 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_TARGET 0 xyzw 0 TARGET float xyzw
+//
+ps_4_0
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_input_ps linear v1.xy
+dcl_output o0.xyzw
+dcl_temps 1
+sample r0.xyzw, v1.xyxx, t0.xyzw, s0
+mov o0.xyzw, r0.xxxw
+ret
+// Approximately 3 instruction slots used
+#endif
+
+const BYTE g_PS_PassthroughLumAlpha[] =
+{
+ 68, 88, 66, 67, 197, 72,
+ 251, 236, 53, 107, 182, 146,
+ 196, 219, 130, 187, 140, 159,
+ 211, 123, 1, 0, 0, 0,
+ 108, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 220, 0, 0, 0, 52, 1,
+ 0, 0, 104, 1, 0, 0,
+ 240, 1, 0, 0, 82, 68,
+ 69, 70, 160, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0,
+ 28, 0, 0, 0, 0, 4,
+ 255, 255, 0, 1, 0, 0,
+ 108, 0, 0, 0, 92, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 100, 0, 0, 0, 2, 0,
+ 0, 0, 5, 0, 0, 0,
+ 4, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 1, 0, 0, 0, 13, 0,
+ 0, 0, 83, 97, 109, 112,
+ 108, 101, 114, 0, 84, 101,
+ 120, 116, 117, 114, 101, 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, 57,
+ 46, 50, 57, 46, 57, 53,
+ 50, 46, 51, 49, 49, 49,
+ 0, 171, 171, 171, 73, 83,
+ 71, 78, 80, 0, 0, 0,
+ 2, 0, 0, 0, 8, 0,
+ 0, 0, 56, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 15, 0,
+ 0, 0, 68, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 0,
+ 1, 0, 0, 0, 3, 3,
+ 0, 0, 83, 86, 95, 80,
+ 79, 83, 73, 84, 73, 79,
+ 78, 0, 84, 69, 88, 67,
+ 79, 79, 82, 68, 0, 171,
+ 171, 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, 128, 0,
+ 0, 0, 64, 0, 0, 0,
+ 32, 0, 0, 0, 90, 0,
+ 0, 3, 0, 96, 16, 0,
+ 0, 0, 0, 0, 88, 24,
+ 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, 101, 0, 0, 3,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 104, 0, 0, 2,
+ 1, 0, 0, 0, 69, 0,
+ 0, 9, 242, 0, 16, 0,
+ 0, 0, 0, 0, 70, 16,
+ 16, 0, 1, 0, 0, 0,
+ 70, 126, 16, 0, 0, 0,
+ 0, 0, 0, 96, 16, 0,
+ 0, 0, 0, 0, 54, 0,
+ 0, 5, 242, 32, 16, 0,
+ 0, 0, 0, 0, 6, 12,
+ 16, 0, 0, 0, 0, 0,
+ 62, 0, 0, 1, 83, 84,
+ 65, 84, 116, 0, 0, 0,
+ 3, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 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, 1, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/passthroughps.h b/src/libGLESv2/renderer/shaders/compiled/passthroughps.h
new file mode 100644
index 00000000..f231d440
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/passthroughps.h
@@ -0,0 +1,63 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+// fxc /E passthroughps /T ps_2_0 /Fh compiled/passthroughps.h Blit.ps
+//
+//
+// Parameters:
+//
+// sampler2D tex;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------ ----- ----
+// tex s0 1
+//
+
+ ps_2_0
+ dcl t0.xy
+ dcl_2d s0
+ texld r0, t0, s0
+ mov oC0, r0
+
+// approximately 2 instruction slots used (1 texture, 1 arithmetic)
+#endif
+
+const BYTE g_ps20_passthroughps[] =
+{
+ 0, 2, 255, 255, 254, 255,
+ 32, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 75, 0,
+ 0, 0, 0, 2, 255, 255,
+ 1, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 68, 0, 0, 0, 48, 0,
+ 0, 0, 3, 0, 0, 0,
+ 1, 0, 0, 0, 52, 0,
+ 0, 0, 0, 0, 0, 0,
+ 116, 101, 120, 0, 4, 0,
+ 12, 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 112, 115, 95, 50,
+ 95, 48, 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, 57, 46, 50, 57,
+ 46, 57, 53, 50, 46, 51,
+ 49, 49, 49, 0, 31, 0,
+ 0, 2, 0, 0, 0, 128,
+ 0, 0, 3, 176, 31, 0,
+ 0, 2, 0, 0, 0, 144,
+ 0, 8, 15, 160, 66, 0,
+ 0, 3, 0, 0, 15, 128,
+ 0, 0, 228, 176, 0, 8,
+ 228, 160, 1, 0, 0, 2,
+ 0, 8, 15, 128, 0, 0,
+ 228, 128, 255, 255, 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/passthroughrgb11ps.h b/src/libGLESv2/renderer/shaders/compiled/passthroughrgb11ps.h
new file mode 100644
index 00000000..da9ff630
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/passthroughrgb11ps.h
@@ -0,0 +1,155 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+// fxc /E PS_PassthroughRGB /T ps_4_0 /Fh compiled/passthroughrgb11ps.h
+// Passthrough11.hlsl
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim Slot Elements
+// ------------------------------ ---------- ------- ----------- ---- --------
+// Sampler sampler NA NA 0 1
+// Texture texture float4 2d 0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_POSITION 0 xyzw 0 POS float
+// TEXCOORD 0 xy 1 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_TARGET 0 xyzw 0 TARGET float xyzw
+//
+ps_4_0
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_input_ps linear v1.xy
+dcl_output o0.xyzw
+dcl_temps 1
+sample r0.xyzw, v1.xyxx, t0.xyzw, s0
+mov o0.xyz, r0.xyzx
+mov o0.w, l(1.000000)
+ret
+// Approximately 4 instruction slots used
+#endif
+
+const BYTE g_PS_PassthroughRGB[] =
+{
+ 68, 88, 66, 67, 253, 45,
+ 13, 34, 125, 194, 95, 149,
+ 1, 95, 194, 252, 118, 228,
+ 178, 200, 1, 0, 0, 0,
+ 128, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 220, 0, 0, 0, 52, 1,
+ 0, 0, 104, 1, 0, 0,
+ 4, 2, 0, 0, 82, 68,
+ 69, 70, 160, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0,
+ 28, 0, 0, 0, 0, 4,
+ 255, 255, 0, 1, 0, 0,
+ 108, 0, 0, 0, 92, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 100, 0, 0, 0, 2, 0,
+ 0, 0, 5, 0, 0, 0,
+ 4, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 1, 0, 0, 0, 13, 0,
+ 0, 0, 83, 97, 109, 112,
+ 108, 101, 114, 0, 84, 101,
+ 120, 116, 117, 114, 101, 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, 57,
+ 46, 50, 57, 46, 57, 53,
+ 50, 46, 51, 49, 49, 49,
+ 0, 171, 171, 171, 73, 83,
+ 71, 78, 80, 0, 0, 0,
+ 2, 0, 0, 0, 8, 0,
+ 0, 0, 56, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 15, 0,
+ 0, 0, 68, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 0,
+ 1, 0, 0, 0, 3, 3,
+ 0, 0, 83, 86, 95, 80,
+ 79, 83, 73, 84, 73, 79,
+ 78, 0, 84, 69, 88, 67,
+ 79, 79, 82, 68, 0, 171,
+ 171, 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, 148, 0,
+ 0, 0, 64, 0, 0, 0,
+ 37, 0, 0, 0, 90, 0,
+ 0, 3, 0, 96, 16, 0,
+ 0, 0, 0, 0, 88, 24,
+ 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, 101, 0, 0, 3,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 104, 0, 0, 2,
+ 1, 0, 0, 0, 69, 0,
+ 0, 9, 242, 0, 16, 0,
+ 0, 0, 0, 0, 70, 16,
+ 16, 0, 1, 0, 0, 0,
+ 70, 126, 16, 0, 0, 0,
+ 0, 0, 0, 96, 16, 0,
+ 0, 0, 0, 0, 54, 0,
+ 0, 5, 114, 32, 16, 0,
+ 0, 0, 0, 0, 70, 2,
+ 16, 0, 0, 0, 0, 0,
+ 54, 0, 0, 5, 130, 32,
+ 16, 0, 0, 0, 0, 0,
+ 1, 64, 0, 0, 0, 0,
+ 128, 63, 62, 0, 0, 1,
+ 83, 84, 65, 84, 116, 0,
+ 0, 0, 4, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 2, 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, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 2, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/passthroughrgba11ps.h b/src/libGLESv2/renderer/shaders/compiled/passthroughrgba11ps.h
new file mode 100644
index 00000000..55f2fef5
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/passthroughrgba11ps.h
@@ -0,0 +1,144 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+// fxc /E PS_PassthroughRGBA /T ps_4_0 /Fh compiled/passthroughrgba11ps.h
+// Passthrough11.hlsl
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim Slot Elements
+// ------------------------------ ---------- ------- ----------- ---- --------
+// Sampler sampler NA NA 0 1
+// Texture texture float4 2d 0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_POSITION 0 xyzw 0 POS float
+// TEXCOORD 0 xy 1 NONE float xy
+//
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_TARGET 0 xyzw 0 TARGET float xyzw
+//
+ps_4_0
+dcl_sampler s0, mode_default
+dcl_resource_texture2d (float,float,float,float) t0
+dcl_input_ps linear v1.xy
+dcl_output o0.xyzw
+sample o0.xyzw, v1.xyxx, t0.xyzw, s0
+ret
+// Approximately 2 instruction slots used
+#endif
+
+const BYTE g_PS_PassthroughRGBA[] =
+{
+ 68, 88, 66, 67, 152, 86,
+ 225, 107, 155, 83, 216, 13,
+ 154, 212, 144, 5, 82, 74,
+ 90, 98, 1, 0, 0, 0,
+ 80, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 220, 0, 0, 0, 52, 1,
+ 0, 0, 104, 1, 0, 0,
+ 212, 1, 0, 0, 82, 68,
+ 69, 70, 160, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0,
+ 28, 0, 0, 0, 0, 4,
+ 255, 255, 0, 1, 0, 0,
+ 108, 0, 0, 0, 92, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 100, 0, 0, 0, 2, 0,
+ 0, 0, 5, 0, 0, 0,
+ 4, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 1, 0, 0, 0, 13, 0,
+ 0, 0, 83, 97, 109, 112,
+ 108, 101, 114, 0, 84, 101,
+ 120, 116, 117, 114, 101, 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, 57,
+ 46, 50, 57, 46, 57, 53,
+ 50, 46, 51, 49, 49, 49,
+ 0, 171, 171, 171, 73, 83,
+ 71, 78, 80, 0, 0, 0,
+ 2, 0, 0, 0, 8, 0,
+ 0, 0, 56, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 3, 0, 0, 0,
+ 0, 0, 0, 0, 15, 0,
+ 0, 0, 68, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 0,
+ 1, 0, 0, 0, 3, 3,
+ 0, 0, 83, 86, 95, 80,
+ 79, 83, 73, 84, 73, 79,
+ 78, 0, 84, 69, 88, 67,
+ 79, 79, 82, 68, 0, 171,
+ 171, 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, 100, 0,
+ 0, 0, 64, 0, 0, 0,
+ 25, 0, 0, 0, 90, 0,
+ 0, 3, 0, 96, 16, 0,
+ 0, 0, 0, 0, 88, 24,
+ 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, 101, 0, 0, 3,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 69, 0, 0, 9,
+ 242, 32, 16, 0, 0, 0,
+ 0, 0, 70, 16, 16, 0,
+ 1, 0, 0, 0, 70, 126,
+ 16, 0, 0, 0, 0, 0,
+ 0, 96, 16, 0, 0, 0,
+ 0, 0, 62, 0, 0, 1,
+ 83, 84, 65, 84, 116, 0,
+ 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 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, 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,
+ 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
+};
diff --git a/src/libGLESv2/renderer/shaders/compiled/standardvs.h b/src/libGLESv2/renderer/shaders/compiled/standardvs.h
new file mode 100644
index 00000000..8ea892eb
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/compiled/standardvs.h
@@ -0,0 +1,69 @@
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+// fxc /E standardvs /T vs_2_0 /Fh compiled/standardvs.h Blit.vs
+//
+//
+// Parameters:
+//
+// float4 halfPixelSize;
+//
+//
+// Registers:
+//
+// Name Reg Size
+// ------------- ----- ----
+// halfPixelSize c0 1
+//
+
+ vs_2_0
+ def c1, 0.5, -0.5, 1, 0
+ dcl_position v0
+ add oPos, v0, c0
+ mad oT0, v0, c1.xyzz, c1.xxww
+
+// approximately 2 instruction slots used
+#endif
+
+const BYTE g_vs20_standardvs[] =
+{
+ 0, 2, 254, 255, 254, 255,
+ 35, 0, 67, 84, 65, 66,
+ 28, 0, 0, 0, 87, 0,
+ 0, 0, 0, 2, 254, 255,
+ 1, 0, 0, 0, 28, 0,
+ 0, 0, 0, 1, 0, 0,
+ 80, 0, 0, 0, 48, 0,
+ 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 64, 0,
+ 0, 0, 0, 0, 0, 0,
+ 104, 97, 108, 102, 80, 105,
+ 120, 101, 108, 83, 105, 122,
+ 101, 0, 171, 171, 1, 0,
+ 3, 0, 1, 0, 4, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 118, 115, 95, 50,
+ 95, 48, 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, 57, 46, 50, 57,
+ 46, 57, 53, 50, 46, 51,
+ 49, 49, 49, 0, 81, 0,
+ 0, 5, 1, 0, 15, 160,
+ 0, 0, 0, 63, 0, 0,
+ 0, 191, 0, 0, 128, 63,
+ 0, 0, 0, 0, 31, 0,
+ 0, 2, 0, 0, 0, 128,
+ 0, 0, 15, 144, 2, 0,
+ 0, 3, 0, 0, 15, 192,
+ 0, 0, 228, 144, 0, 0,
+ 228, 160, 4, 0, 0, 4,
+ 0, 0, 15, 224, 0, 0,
+ 228, 144, 1, 0, 164, 160,
+ 1, 0, 240, 160, 255, 255,
+ 0, 0
+};
diff --git a/src/libGLESv2/renderer/shaders/generate_shaders.bat b/src/libGLESv2/renderer/shaders/generate_shaders.bat
new file mode 100644
index 00000000..04ef1368
--- /dev/null
+++ b/src/libGLESv2/renderer/shaders/generate_shaders.bat
@@ -0,0 +1,24 @@
+@ECHO OFF
+REM
+REM Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+REM Use of this source code is governed by a BSD-style license that can be
+REM found in the LICENSE file.
+REM
+
+PATH %PATH%;%DXSDK_DIR%\Utilities\bin\x86
+
+fxc /E standardvs /T vs_2_0 /Fh compiled/standardvs.h Blit.vs
+fxc /E flipyvs /T vs_2_0 /Fh compiled/flipyvs.h Blit.vs
+fxc /E passthroughps /T ps_2_0 /Fh compiled/passthroughps.h Blit.ps
+fxc /E luminanceps /T ps_2_0 /Fh compiled/luminanceps.h Blit.ps
+fxc /E componentmaskps /T ps_2_0 /Fh compiled/componentmaskps.h Blit.ps
+
+fxc /E VS_Passthrough /T vs_4_0 /Fh compiled/passthrough11vs.h Passthrough11.hlsl
+fxc /E PS_PassthroughRGBA /T ps_4_0 /Fh compiled/passthroughrgba11ps.h Passthrough11.hlsl
+fxc /E PS_PassthroughRGB /T ps_4_0 /Fh compiled/passthroughrgb11ps.h Passthrough11.hlsl
+fxc /E PS_PassthroughLum /T ps_4_0 /Fh compiled/passthroughlum11ps.h Passthrough11.hlsl
+fxc /E PS_PassthroughLumAlpha /T ps_4_0 /Fh compiled/passthroughlumalpha11ps.h Passthrough11.hlsl
+
+fxc /E VS_Clear /T vs_4_0 /Fh compiled/clear11vs.h Clear11.hlsl
+fxc /E PS_ClearSingle /T ps_4_0 /Fh compiled/clearsingle11ps.h Clear11.hlsl
+fxc /E PS_ClearMultiple /T ps_4_0 /Fh compiled/clearmultiple11ps.h Clear11.hlsl
diff --git a/src/libGLESv2/renderer/vertexconversion.h b/src/libGLESv2/renderer/vertexconversion.h
new file mode 100644
index 00000000..590b9d48
--- /dev/null
+++ b/src/libGLESv2/renderer/vertexconversion.h
@@ -0,0 +1,203 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// vertexconversion.h: A library of vertex conversion classes that can be used to build
+// the FormatConverter objects used by the buffer conversion system.
+
+#ifndef LIBGLESV2_VERTEXCONVERSION_H_
+#define LIBGLESV2_VERTEXCONVERSION_H_
+
+namespace rx
+{
+
+// Conversion types:
+// static const bool identity: true if this is an identity transform, false otherwise
+// static U convert(T): convert a single element from the input type to the output type
+// typedef ... OutputType: the type produced by this conversion
+
+template <class T>
+struct Identity
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return x;
+ }
+};
+
+template <class FromT, class ToT>
+struct Cast
+{
+ static const bool identity = false;
+
+ typedef ToT OutputType;
+
+ static ToT convert(FromT x)
+ {
+ return static_cast<ToT>(x);
+ }
+};
+
+template <class T>
+struct Cast<T, T>
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return static_cast<T>(x);
+ }
+};
+
+template <class T>
+struct Normalize
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(T x)
+ {
+ typedef std::numeric_limits<T> NL;
+ float f = static_cast<float>(x);
+
+ if (NL::is_signed)
+ {
+ // const float => VC2008 computes it at compile time
+ // static const float => VC2008 computes it the first time we get here, stores it to memory with static guard and all that.
+ const float divisor = 1.0f/(2*static_cast<float>(NL::max())+1);
+ return (2*f+1)*divisor;
+ }
+ else
+ {
+ return f/NL::max();
+ }
+ }
+};
+
+template <class FromType, std::size_t ScaleBits>
+struct FixedToFloat
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(FromType x)
+ {
+ const float divisor = 1.0f / static_cast<float>(static_cast<FromType>(1) << ScaleBits);
+ return static_cast<float>(x) * divisor;
+ }
+};
+
+// Widen types:
+// static const unsigned int initialWidth: number of components before conversion
+// static const unsigned int finalWidth: number of components after conversion
+
+// Float is supported at any size.
+template <std::size_t N>
+struct NoWiden
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N;
+};
+
+// SHORT, norm-SHORT, norm-UNSIGNED_SHORT are supported but only with 2 or 4 components
+template <std::size_t N>
+struct WidenToEven
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N+(N&1);
+};
+
+template <std::size_t N>
+struct WidenToFour
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = 4;
+};
+
+// Most types have 0 and 1 that are just that.
+template <class T>
+struct SimpleDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return static_cast<T>(1); }
+};
+
+// But normalised types only store [0,1] or [-1,1] so 1.0 is represented by the max value.
+template <class T>
+struct NormalizedDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return std::numeric_limits<T>::max(); }
+};
+
+// Converter:
+// static const bool identity: true if this is an identity transform (with no widening)
+// static const std::size_t finalSize: number of bytes per output vertex
+// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert an array of vertices. Input may be strided, but output will be unstrided.
+
+template <class InT, class WidenRule, class Converter, class DefaultValueRule = SimpleDefaultValues<InT> >
+struct VertexDataConverter
+{
+ typedef typename Converter::OutputType OutputType;
+ typedef InT InputType;
+
+ static const bool identity = (WidenRule::initialWidth == WidenRule::finalWidth) && Converter::identity;
+ static const std::size_t finalSize = WidenRule::finalWidth * sizeof(OutputType);
+
+ static void convertArray(const InputType *in, std::size_t stride, std::size_t n, OutputType *out)
+ {
+ for (std::size_t i = 0; i < n; i++)
+ {
+ const InputType *ein = pointerAddBytes(in, i * stride);
+
+ copyComponent(out, ein, 0, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 1, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 2, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 3, static_cast<OutputType>(DefaultValueRule::one()));
+
+ out += WidenRule::finalWidth;
+ }
+ }
+
+ static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out)
+ {
+ return convertArray(static_cast<const InputType*>(in), stride, n, static_cast<OutputType*>(out));
+ }
+
+ private:
+ // Advance the given pointer by a number of bytes (not pointed-to elements).
+ template <class T>
+ static T *pointerAddBytes(T *basePtr, std::size_t numBytes)
+ {
+ return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(basePtr) + numBytes);
+ }
+
+ static void copyComponent(OutputType *out, const InputType *in, std::size_t elementindex, OutputType defaultvalue)
+ {
+ if (WidenRule::finalWidth > elementindex)
+ {
+ if (WidenRule::initialWidth > elementindex)
+ {
+ out[elementindex] = Converter::convert(in[elementindex]);
+ }
+ else
+ {
+ out[elementindex] = defaultvalue;
+ }
+ }
+ }
+};
+
+}
+
+#endif // LIBGLESV2_VERTEXCONVERSION_H_
diff --git a/src/libGLESv2/resource.h b/src/libGLESv2/resource.h
new file mode 100644
index 00000000..39adaad0
--- /dev/null
+++ b/src/libGLESv2/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by libGLESv2.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/libGLESv2/utilities.cpp b/src/libGLESv2/utilities.cpp
new file mode 100644
index 00000000..32df49e6
--- /dev/null
+++ b/src/libGLESv2/utilities.cpp
@@ -0,0 +1,769 @@
+#include "precompiled.h"
+//
+// 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.
+//
+
+// utilities.cpp: Conversion functions and other utility routines.
+
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/mathutil.h"
+
+namespace gl
+{
+
+int UniformComponentCount(GLenum type)
+{
+ switch (type)
+ {
+ case GL_BOOL:
+ case GL_FLOAT:
+ case GL_INT:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ return 1;
+ case GL_BOOL_VEC2:
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ return 2;
+ case GL_INT_VEC3:
+ case GL_FLOAT_VEC3:
+ case GL_BOOL_VEC3:
+ return 3;
+ case GL_BOOL_VEC4:
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_FLOAT_MAT2:
+ return 4;
+ case GL_FLOAT_MAT3:
+ return 9;
+ case GL_FLOAT_MAT4:
+ return 16;
+ default:
+ UNREACHABLE();
+ }
+
+ return 0;
+}
+
+GLenum UniformComponentType(GLenum type)
+{
+ switch(type)
+ {
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ return GL_BOOL;
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT4:
+ return GL_FLOAT;
+ case GL_INT:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ return GL_INT;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_NONE;
+}
+
+size_t UniformComponentSize(GLenum type)
+{
+ switch(type)
+ {
+ case GL_BOOL: return sizeof(GLint);
+ case GL_FLOAT: return sizeof(GLfloat);
+ case GL_INT: return sizeof(GLint);
+ default: UNREACHABLE();
+ }
+
+ return 0;
+}
+
+size_t UniformInternalSize(GLenum type)
+{
+ // Expanded to 4-element vectors
+ return UniformComponentSize(UniformComponentType(type)) * VariableRowCount(type) * 4;
+}
+
+size_t UniformExternalSize(GLenum type)
+{
+ return UniformComponentSize(UniformComponentType(type)) * UniformComponentCount(type);
+}
+
+int VariableRowCount(GLenum type)
+{
+ switch (type)
+ {
+ case GL_NONE:
+ return 0;
+ case GL_BOOL:
+ case GL_FLOAT:
+ case GL_INT:
+ case GL_BOOL_VEC2:
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_FLOAT_VEC3:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ return 1;
+ case GL_FLOAT_MAT2:
+ return 2;
+ case GL_FLOAT_MAT3:
+ return 3;
+ case GL_FLOAT_MAT4:
+ return 4;
+ default:
+ UNREACHABLE();
+ }
+
+ return 0;
+}
+
+int VariableColumnCount(GLenum type)
+{
+ switch (type)
+ {
+ case GL_NONE:
+ return 0;
+ case GL_BOOL:
+ case GL_FLOAT:
+ case GL_INT:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ return 1;
+ case GL_BOOL_VEC2:
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_FLOAT_MAT2:
+ return 2;
+ case GL_INT_VEC3:
+ case GL_FLOAT_VEC3:
+ case GL_BOOL_VEC3:
+ case GL_FLOAT_MAT3:
+ return 3;
+ case GL_BOOL_VEC4:
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_FLOAT_MAT4:
+ return 4;
+ default:
+ UNREACHABLE();
+ }
+
+ return 0;
+}
+
+int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize)
+{
+ ASSERT(allocationSize <= bitsSize);
+
+ unsigned int mask = std::numeric_limits<unsigned int>::max() >> (std::numeric_limits<unsigned int>::digits - allocationSize);
+
+ for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++)
+ {
+ if ((*bits & mask) == 0)
+ {
+ *bits |= mask;
+ return i;
+ }
+
+ mask <<= 1;
+ }
+
+ return -1;
+}
+
+GLsizei ComputePitch(GLsizei width, GLint internalformat, GLint alignment)
+{
+ ASSERT(alignment > 0 && isPow2(alignment));
+
+ GLsizei rawPitch = ComputePixelSize(internalformat) * width;
+ return (rawPitch + alignment - 1) & ~(alignment - 1);
+}
+
+GLsizei ComputeCompressedPitch(GLsizei width, GLenum internalformat)
+{
+ return ComputeCompressedSize(width, 1, internalformat);
+}
+
+GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ return 8 * ((width + 3) / 4) * ((height + 3) / 4);
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
+ return 16 * ((width + 3) / 4) * ((height + 3) / 4);
+ default:
+ return 0;
+ }
+}
+
+GLsizei ComputeTypeSize(GLenum type)
+{
+ switch (type)
+ {
+ case GL_BYTE: return 1;
+ case GL_UNSIGNED_BYTE: return 1;
+ case GL_SHORT: return 2;
+ case GL_UNSIGNED_SHORT: return 2;
+ case GL_INT: return 4;
+ case GL_UNSIGNED_INT: return 4;
+ case GL_FLOAT: return 4;
+ case GL_HALF_FLOAT_OES: return 2;
+ case GL_UNSIGNED_SHORT_5_6_5: return 2;
+ case GL_UNSIGNED_SHORT_4_4_4_4: return 2;
+ case GL_UNSIGNED_SHORT_5_5_5_1: return 2;
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return 2;
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return 2;
+ case GL_UNSIGNED_INT_2_10_10_10_REV_EXT: return 4;
+ case GL_UNSIGNED_INT_24_8_OES: return 4;
+ default: UNREACHABLE(); return 0;
+ }
+}
+
+bool IsCompressed(GLenum format)
+{
+ if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
+ format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE ||
+ format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool IsDepthTexture(GLenum format)
+{
+ if (format == GL_DEPTH_COMPONENT ||
+ format == GL_DEPTH_STENCIL_OES ||
+ format == GL_DEPTH_COMPONENT16 ||
+ format == GL_DEPTH_COMPONENT32_OES ||
+ format == GL_DEPTH24_STENCIL8_OES)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool IsStencilTexture(GLenum format)
+{
+ if (format == GL_DEPTH_STENCIL_OES ||
+ format == GL_DEPTH24_STENCIL8_OES)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void MakeValidSize(bool isImage, bool isCompressed, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset)
+{
+ int upsampleCount = 0;
+
+ if (isCompressed)
+ {
+ // Don't expand the size of full textures that are at least 4x4
+ // already.
+ if (isImage || *requestWidth < 4 || *requestHeight < 4)
+ {
+ while (*requestWidth % 4 != 0 || *requestHeight % 4 != 0)
+ {
+ *requestWidth <<= 1;
+ *requestHeight <<= 1;
+ upsampleCount++;
+ }
+ }
+ }
+ *levelOffset = upsampleCount;
+}
+
+// Returns the size, in bytes, of a single texel in an Image
+int ComputePixelSize(GLint internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_ALPHA8_EXT: return sizeof(unsigned char);
+ case GL_LUMINANCE8_EXT: return sizeof(unsigned char);
+ case GL_ALPHA32F_EXT: return sizeof(float);
+ case GL_LUMINANCE32F_EXT: return sizeof(float);
+ case GL_ALPHA16F_EXT: return sizeof(unsigned short);
+ case GL_LUMINANCE16F_EXT: return sizeof(unsigned short);
+ case GL_LUMINANCE8_ALPHA8_EXT: return sizeof(unsigned char) * 2;
+ case GL_LUMINANCE_ALPHA32F_EXT: return sizeof(float) * 2;
+ case GL_LUMINANCE_ALPHA16F_EXT: return sizeof(unsigned short) * 2;
+ case GL_RGB8_OES: return sizeof(unsigned char) * 3;
+ case GL_RGB565: return sizeof(unsigned short);
+ case GL_RGB32F_EXT: return sizeof(float) * 3;
+ case GL_RGB16F_EXT: return sizeof(unsigned short) * 3;
+ case GL_RGBA8_OES: return sizeof(unsigned char) * 4;
+ case GL_RGBA4: return sizeof(unsigned short);
+ case GL_RGB5_A1: return sizeof(unsigned short);
+ case GL_RGBA32F_EXT: return sizeof(float) * 4;
+ case GL_RGBA16F_EXT: return sizeof(unsigned short) * 4;
+ case GL_BGRA8_EXT: return sizeof(unsigned char) * 4;
+ case GL_BGRA4_ANGLEX: return sizeof(unsigned short);
+ case GL_BGR5_A1_ANGLEX: return sizeof(unsigned short);
+ default: UNREACHABLE();
+ }
+
+ return 0;
+}
+
+bool IsCubemapTextureTarget(GLenum target)
+{
+ return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
+}
+
+bool IsInternalTextureTarget(GLenum target)
+{
+ return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target);
+}
+
+GLint ConvertSizedInternalFormat(GLenum format, GLenum type)
+{
+ switch (format)
+ {
+ case GL_ALPHA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: return GL_ALPHA8_EXT;
+ case GL_FLOAT: return GL_ALPHA32F_EXT;
+ case GL_HALF_FLOAT_OES: return GL_ALPHA16F_EXT;
+ default: UNIMPLEMENTED();
+ }
+ break;
+ case GL_LUMINANCE:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_EXT;
+ case GL_FLOAT: return GL_LUMINANCE32F_EXT;
+ case GL_HALF_FLOAT_OES: return GL_LUMINANCE16F_EXT;
+ default: UNIMPLEMENTED();
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_ALPHA8_EXT;
+ case GL_FLOAT: return GL_LUMINANCE_ALPHA32F_EXT;
+ case GL_HALF_FLOAT_OES: return GL_LUMINANCE_ALPHA16F_EXT;
+ default: UNIMPLEMENTED();
+ }
+ break;
+ case GL_RGB:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: return GL_RGB8_OES;
+ case GL_UNSIGNED_SHORT_5_6_5: return GL_RGB565;
+ case GL_FLOAT: return GL_RGB32F_EXT;
+ case GL_HALF_FLOAT_OES: return GL_RGB16F_EXT;
+ default: UNIMPLEMENTED();
+ }
+ break;
+ case GL_RGBA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: return GL_RGBA8_OES;
+ case GL_UNSIGNED_SHORT_4_4_4_4: return GL_RGBA4;
+ case GL_UNSIGNED_SHORT_5_5_5_1: return GL_RGB5_A1;
+ case GL_FLOAT: return GL_RGBA32F_EXT;
+ case GL_HALF_FLOAT_OES: return GL_RGBA16F_EXT;
+ break;
+ default: UNIMPLEMENTED();
+ }
+ break;
+ case GL_BGRA_EXT:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: return GL_BGRA8_EXT;
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return GL_BGRA4_ANGLEX;
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return GL_BGR5_A1_ANGLEX;
+ default: UNIMPLEMENTED();
+ }
+ 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:
+ return format;
+ case GL_DEPTH_COMPONENT:
+ switch (type)
+ {
+ case GL_UNSIGNED_SHORT: return GL_DEPTH_COMPONENT16;
+ case GL_UNSIGNED_INT: return GL_DEPTH_COMPONENT32_OES;
+ default: UNIMPLEMENTED();
+ }
+ break;
+ case GL_DEPTH_STENCIL_OES:
+ switch (type)
+ {
+ case GL_UNSIGNED_INT_24_8_OES: return GL_DEPTH24_STENCIL8_OES;
+ default: UNIMPLEMENTED();
+ }
+ break;
+ default:
+ UNIMPLEMENTED();
+ }
+
+ return GL_NONE;
+}
+
+GLenum ExtractFormat(GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_RGB565: return GL_RGB;
+ case GL_RGBA4: return GL_RGBA;
+ case GL_RGB5_A1: return GL_RGBA;
+ case GL_RGB8_OES: return GL_RGB;
+ case GL_RGBA8_OES: return GL_RGBA;
+ case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA;
+ case GL_LUMINANCE8_EXT: return GL_LUMINANCE;
+ case GL_ALPHA8_EXT: return GL_ALPHA;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE;
+ case GL_RGBA32F_EXT: return GL_RGBA;
+ case GL_RGB32F_EXT: return GL_RGB;
+ case GL_ALPHA32F_EXT: return GL_ALPHA;
+ case GL_LUMINANCE32F_EXT: return GL_LUMINANCE;
+ case GL_LUMINANCE_ALPHA32F_EXT: return GL_LUMINANCE_ALPHA;
+ case GL_RGBA16F_EXT: return GL_RGBA;
+ case GL_RGB16F_EXT: return GL_RGB;
+ case GL_ALPHA16F_EXT: return GL_ALPHA;
+ case GL_LUMINANCE16F_EXT: return GL_LUMINANCE;
+ case GL_LUMINANCE_ALPHA16F_EXT: return GL_LUMINANCE_ALPHA;
+ case GL_BGRA8_EXT: return GL_BGRA_EXT;
+ case GL_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT;
+ case GL_DEPTH_COMPONENT32_OES: return GL_DEPTH_COMPONENT;
+ case GL_DEPTH24_STENCIL8_OES: return GL_DEPTH_STENCIL_OES;
+ default: return GL_NONE; // Unsupported
+ }
+}
+
+GLenum ExtractType(GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_RGB565: return GL_UNSIGNED_SHORT_5_6_5;
+ case GL_RGBA4: return GL_UNSIGNED_SHORT_4_4_4_4;
+ case GL_RGB5_A1: return GL_UNSIGNED_SHORT_5_5_5_1;
+ case GL_RGB8_OES: return GL_UNSIGNED_BYTE;
+ case GL_RGBA8_OES: return GL_UNSIGNED_BYTE;
+ case GL_LUMINANCE8_ALPHA8_EXT: return GL_UNSIGNED_BYTE;
+ case GL_LUMINANCE8_EXT: return GL_UNSIGNED_BYTE;
+ case GL_ALPHA8_EXT: return GL_UNSIGNED_BYTE;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE;
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return GL_UNSIGNED_BYTE;
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return GL_UNSIGNED_BYTE;
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return GL_UNSIGNED_BYTE;
+ case GL_RGBA32F_EXT: return GL_FLOAT;
+ case GL_RGB32F_EXT: return GL_FLOAT;
+ case GL_ALPHA32F_EXT: return GL_FLOAT;
+ case GL_LUMINANCE32F_EXT: return GL_FLOAT;
+ case GL_LUMINANCE_ALPHA32F_EXT: return GL_FLOAT;
+ case GL_RGBA16F_EXT: return GL_HALF_FLOAT_OES;
+ case GL_RGB16F_EXT: return GL_HALF_FLOAT_OES;
+ case GL_ALPHA16F_EXT: return GL_HALF_FLOAT_OES;
+ case GL_LUMINANCE16F_EXT: return GL_HALF_FLOAT_OES;
+ case GL_LUMINANCE_ALPHA16F_EXT: return GL_HALF_FLOAT_OES;
+ case GL_BGRA8_EXT: return GL_UNSIGNED_BYTE;
+ case GL_DEPTH_COMPONENT16: return GL_UNSIGNED_SHORT;
+ case GL_DEPTH_COMPONENT32_OES: return GL_UNSIGNED_INT;
+ case GL_DEPTH24_STENCIL8_OES: return GL_UNSIGNED_INT_24_8_OES;
+ default: return GL_NONE; // Unsupported
+ }
+}
+
+bool IsColorRenderable(GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ return true;
+ case GL_DEPTH_COMPONENT16:
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES:
+ return false;
+ case GL_BGRA8_EXT:
+ return true;
+ default:
+ UNIMPLEMENTED();
+ }
+
+ return false;
+}
+
+bool IsDepthRenderable(GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_DEPTH_COMPONENT16:
+ case GL_DEPTH24_STENCIL8_OES:
+ return true;
+ case GL_STENCIL_INDEX8:
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ return false;
+ default:
+ UNIMPLEMENTED();
+ }
+
+ return false;
+}
+
+bool IsStencilRenderable(GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES:
+ return true;
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ case GL_DEPTH_COMPONENT16:
+ return false;
+ default:
+ UNIMPLEMENTED();
+ }
+
+ return false;
+}
+
+bool IsFloat32Format(GLint internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_RGBA32F_EXT:
+ case GL_RGB32F_EXT:
+ case GL_ALPHA32F_EXT:
+ case GL_LUMINANCE32F_EXT:
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool IsFloat16Format(GLint internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_RGBA16F_EXT:
+ case GL_RGB16F_EXT:
+ case GL_ALPHA16F_EXT:
+ case GL_LUMINANCE16F_EXT:
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+unsigned int GetAlphaSize(GLenum colorFormat)
+{
+ switch (colorFormat)
+ {
+ case GL_RGBA16F_EXT:
+ return 16;
+ case GL_RGBA32F_EXT:
+ return 32;
+ case GL_RGBA4:
+ return 4;
+ case GL_RGBA8_OES:
+ case GL_BGRA8_EXT:
+ return 8;
+ case GL_RGB5_A1:
+ return 1;
+ case GL_RGB8_OES:
+ case GL_RGB565:
+ case GL_RGB32F_EXT:
+ case GL_RGB16F_EXT:
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetRedSize(GLenum colorFormat)
+{
+ switch (colorFormat)
+ {
+ case GL_RGBA16F_EXT:
+ case GL_RGB16F_EXT:
+ return 16;
+ case GL_RGBA32F_EXT:
+ case GL_RGB32F_EXT:
+ return 32;
+ case GL_RGBA4:
+ return 4;
+ case GL_RGBA8_OES:
+ case GL_BGRA8_EXT:
+ case GL_RGB8_OES:
+ return 8;
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ return 5;
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetGreenSize(GLenum colorFormat)
+{
+ switch (colorFormat)
+ {
+ case GL_RGBA16F_EXT:
+ case GL_RGB16F_EXT:
+ return 16;
+ case GL_RGBA32F_EXT:
+ case GL_RGB32F_EXT:
+ return 32;
+ case GL_RGBA4:
+ return 4;
+ case GL_RGBA8_OES:
+ case GL_BGRA8_EXT:
+ case GL_RGB8_OES:
+ return 8;
+ case GL_RGB5_A1:
+ return 5;
+ case GL_RGB565:
+ return 6;
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetBlueSize(GLenum colorFormat)
+{
+ switch (colorFormat)
+ {
+ case GL_RGBA16F_EXT:
+ case GL_RGB16F_EXT:
+ return 16;
+ case GL_RGBA32F_EXT:
+ case GL_RGB32F_EXT:
+ return 32;
+ case GL_RGBA4:
+ return 4;
+ case GL_RGBA8_OES:
+ case GL_BGRA8_EXT:
+ case GL_RGB8_OES:
+ return 8;
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ return 5;
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetDepthSize(GLenum depthFormat)
+{
+ switch (depthFormat)
+ {
+ case GL_DEPTH_COMPONENT16: return 16;
+ case GL_DEPTH_COMPONENT32_OES: return 32;
+ case GL_DEPTH24_STENCIL8_OES: return 24;
+ default: return 0;
+ }
+}
+
+unsigned int GetStencilSize(GLenum stencilFormat)
+{
+ switch (stencilFormat)
+ {
+ case GL_DEPTH24_STENCIL8_OES: return 8;
+ default: return 0;
+ }
+}
+
+bool IsTriangleMode(GLenum drawMode)
+{
+ switch (drawMode)
+ {
+ case GL_TRIANGLES:
+ case GL_TRIANGLE_FAN:
+ case GL_TRIANGLE_STRIP:
+ return true;
+ case GL_POINTS:
+ case GL_LINES:
+ case GL_LINE_LOOP:
+ case GL_LINE_STRIP:
+ return false;
+ default: UNREACHABLE();
+ }
+
+ return false;
+}
+
+}
+
+std::string getTempPath()
+{
+ char path[MAX_PATH];
+ DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
+ if (pathLen == 0)
+ {
+ UNREACHABLE();
+ return std::string();
+ }
+
+ UINT unique = GetTempFileNameA(path, "sh", 0, path);
+ if (unique == 0)
+ {
+ UNREACHABLE();
+ return std::string();
+ }
+
+ return path;
+}
+
+void writeFile(const char* path, const void* content, size_t size)
+{
+ FILE* file = fopen(path, "w");
+ if (!file)
+ {
+ UNREACHABLE();
+ return;
+ }
+
+ fwrite(content, sizeof(char), size, file);
+ fclose(file);
+}
diff --git a/src/libGLESv2/utilities.h b/src/libGLESv2/utilities.h
new file mode 100644
index 00000000..ed663ebc
--- /dev/null
+++ b/src/libGLESv2/utilities.h
@@ -0,0 +1,67 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// utilities.h: Conversion functions and other utility routines.
+
+#ifndef LIBGLESV2_UTILITIES_H
+#define LIBGLESV2_UTILITIES_H
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <string>
+
+namespace gl
+{
+
+struct Color;
+
+int UniformComponentCount(GLenum type);
+GLenum UniformComponentType(GLenum type);
+size_t UniformInternalSize(GLenum type);
+size_t UniformExternalSize(GLenum type);
+int VariableRowCount(GLenum type);
+int VariableColumnCount(GLenum type);
+
+int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);
+
+void MakeValidSize(bool isImage, bool isCompressed, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset);
+int ComputePixelSize(GLint internalformat);
+GLsizei ComputePitch(GLsizei width, GLint internalformat, GLint alignment);
+GLsizei ComputeCompressedPitch(GLsizei width, GLenum format);
+GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format);
+GLsizei ComputeTypeSize(GLenum type);
+bool IsCompressed(GLenum format);
+bool IsDepthTexture(GLenum format);
+bool IsStencilTexture(GLenum format);
+bool IsCubemapTextureTarget(GLenum target);
+bool IsInternalTextureTarget(GLenum target);
+GLint ConvertSizedInternalFormat(GLenum format, GLenum type);
+GLenum ExtractFormat(GLenum internalformat);
+GLenum ExtractType(GLenum internalformat);
+
+bool IsColorRenderable(GLenum internalformat);
+bool IsDepthRenderable(GLenum internalformat);
+bool IsStencilRenderable(GLenum internalformat);
+
+bool IsFloat32Format(GLint internalformat);
+bool IsFloat16Format(GLint internalformat);
+
+GLuint GetAlphaSize(GLenum colorFormat);
+GLuint GetRedSize(GLenum colorFormat);
+GLuint GetGreenSize(GLenum colorFormat);
+GLuint GetBlueSize(GLenum colorFormat);
+GLuint GetDepthSize(GLenum depthFormat);
+GLuint GetStencilSize(GLenum stencilFormat);
+bool IsTriangleMode(GLenum drawMode);
+
+}
+
+std::string getTempPath();
+void writeFile(const char* path, const void* data, size_t size);
+
+#endif // LIBGLESV2_UTILITIES_H
diff --git a/src/preprocessor.target.darwin-arm.mk b/src/preprocessor.target.darwin-arm.mk
new file mode 100644
index 00000000..31c9ec76
--- /dev/null
+++ b/src/preprocessor.target.darwin-arm.mk
@@ -0,0 +1,272 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_preprocessor_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/preprocessor/DiagnosticsBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveHandlerBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/ExpressionParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Input.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Lexer.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Macro.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/MacroExpander.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Preprocessor.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Token.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Tokenizer.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_preprocessor_gyp
+
+# Alias gyp target name.
+.PHONY: preprocessor
+preprocessor: third_party_angle_dx11_src_preprocessor_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/preprocessor.target.darwin-mips.mk b/src/preprocessor.target.darwin-mips.mk
new file mode 100644
index 00000000..3fc00116
--- /dev/null
+++ b/src/preprocessor.target.darwin-mips.mk
@@ -0,0 +1,268 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_preprocessor_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/preprocessor/DiagnosticsBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveHandlerBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/ExpressionParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Input.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Lexer.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Macro.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/MacroExpander.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Preprocessor.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Token.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Tokenizer.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_preprocessor_gyp
+
+# Alias gyp target name.
+.PHONY: preprocessor
+preprocessor: third_party_angle_dx11_src_preprocessor_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/preprocessor.target.darwin-x86.mk b/src/preprocessor.target.darwin-x86.mk
new file mode 100644
index 00000000..50f920b9
--- /dev/null
+++ b/src/preprocessor.target.darwin-x86.mk
@@ -0,0 +1,272 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_preprocessor_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/preprocessor/DiagnosticsBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveHandlerBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/ExpressionParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Input.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Lexer.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Macro.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/MacroExpander.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Preprocessor.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Token.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Tokenizer.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer \
+ -fno-unwind-tables \
+ -fno-asynchronous-unwind-tables
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_preprocessor_gyp
+
+# Alias gyp target name.
+.PHONY: preprocessor
+preprocessor: third_party_angle_dx11_src_preprocessor_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/preprocessor.target.linux-arm.mk b/src/preprocessor.target.linux-arm.mk
new file mode 100644
index 00000000..31c9ec76
--- /dev/null
+++ b/src/preprocessor.target.linux-arm.mk
@@ -0,0 +1,272 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_preprocessor_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/preprocessor/DiagnosticsBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveHandlerBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/ExpressionParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Input.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Lexer.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Macro.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/MacroExpander.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Preprocessor.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Token.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Tokenizer.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_preprocessor_gyp
+
+# Alias gyp target name.
+.PHONY: preprocessor
+preprocessor: third_party_angle_dx11_src_preprocessor_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/preprocessor.target.linux-mips.mk b/src/preprocessor.target.linux-mips.mk
new file mode 100644
index 00000000..3fc00116
--- /dev/null
+++ b/src/preprocessor.target.linux-mips.mk
@@ -0,0 +1,268 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_preprocessor_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/preprocessor/DiagnosticsBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveHandlerBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/ExpressionParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Input.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Lexer.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Macro.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/MacroExpander.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Preprocessor.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Token.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Tokenizer.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_preprocessor_gyp
+
+# Alias gyp target name.
+.PHONY: preprocessor
+preprocessor: third_party_angle_dx11_src_preprocessor_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/preprocessor.target.linux-x86.mk b/src/preprocessor.target.linux-x86.mk
new file mode 100644
index 00000000..50f920b9
--- /dev/null
+++ b/src/preprocessor.target.linux-x86.mk
@@ -0,0 +1,272 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_preprocessor_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/preprocessor/DiagnosticsBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveHandlerBase.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/DirectiveParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/ExpressionParser.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Input.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Lexer.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Macro.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/MacroExpander.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Preprocessor.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Token.cpp \
+ third_party/angle_dx11/src/compiler/preprocessor/Tokenizer.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer \
+ -fno-unwind-tables \
+ -fno-asynchronous-unwind-tables
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_preprocessor_gyp
+
+# Alias gyp target name.
+.PHONY: preprocessor
+preprocessor: third_party_angle_dx11_src_preprocessor_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/third_party/compiler/ArrayBoundsClamper.cpp b/src/third_party/compiler/ArrayBoundsClamper.cpp
new file mode 100644
index 00000000..288f5529
--- /dev/null
+++ b/src/third_party/compiler/ArrayBoundsClamper.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "third_party/compiler/ArrayBoundsClamper.h"
+
+// The built-in 'clamp' instruction only accepts floats and returns a float. I
+// iterated a few times with our driver team who examined the output from our
+// compiler - they said the multiple casts generates more code than a single
+// function call. An inline ternary operator might have been better, but since
+// the index value might be an expression itself, we'd have to make temporary
+// variables to avoid evaluating the expression multiple times. And making
+// temporary variables was difficult because ANGLE would then need to make more
+// brutal changes to the expression tree.
+
+const char* kIntClampBegin = "// BEGIN: Generated code for array bounds clamping\n\n";
+const char* kIntClampEnd = "// END: Generated code for array bounds clamping\n\n";
+const char* kIntClampDefinition = "int webgl_int_clamp(int value, int minValue, int maxValue) { return ((value < minValue) ? minValue : ((value > maxValue) ? maxValue : value)); }\n\n";
+
+namespace {
+
+class ArrayBoundsClamperMarker : public TIntermTraverser {
+public:
+ ArrayBoundsClamperMarker()
+ : mNeedsClamp(false)
+ {
+ }
+
+ virtual bool visitBinary(Visit visit, TIntermBinary* node)
+ {
+ if (node->getOp() == EOpIndexIndirect)
+ {
+ TIntermTyped* left = node->getLeft();
+ if (left->isArray() || left->isVector() || left->isMatrix())
+ {
+ node->setAddIndexClamp();
+ mNeedsClamp = true;
+ }
+ }
+ return true;
+ }
+
+ bool GetNeedsClamp() { return mNeedsClamp; }
+
+private:
+ bool mNeedsClamp;
+};
+
+} // anonymous namespace
+
+ArrayBoundsClamper::ArrayBoundsClamper()
+ : mClampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC)
+ , mArrayBoundsClampDefinitionNeeded(false)
+{
+}
+
+void ArrayBoundsClamper::SetClampingStrategy(ShArrayIndexClampingStrategy clampingStrategy)
+{
+ mClampingStrategy = clampingStrategy;
+}
+
+void ArrayBoundsClamper::MarkIndirectArrayBoundsForClamping(TIntermNode* root)
+{
+ ASSERT(root);
+
+ ArrayBoundsClamperMarker clamper;
+ root->traverse(&clamper);
+ if (clamper.GetNeedsClamp())
+ {
+ SetArrayBoundsClampDefinitionNeeded();
+ }
+}
+
+void ArrayBoundsClamper::OutputClampingFunctionDefinition(TInfoSinkBase& out) const
+{
+ if (!mArrayBoundsClampDefinitionNeeded)
+ {
+ return;
+ }
+ if (mClampingStrategy != SH_CLAMP_WITH_USER_DEFINED_INT_CLAMP_FUNCTION)
+ {
+ return;
+ }
+ out << kIntClampBegin << kIntClampDefinition << kIntClampEnd;
+}
diff --git a/src/third_party/compiler/ArrayBoundsClamper.h b/src/third_party/compiler/ArrayBoundsClamper.h
new file mode 100644
index 00000000..0d4e1a37
--- /dev/null
+++ b/src/third_party/compiler/ArrayBoundsClamper.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef THIRD_PARTY_COMPILER_ARRAY_BOUNDS_CLAMPER_H_
+#define THIRD_PARTY_COMPILER_ARRAY_BOUNDS_CLAMPER_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/intermediate.h"
+
+class ArrayBoundsClamper {
+public:
+ ArrayBoundsClamper();
+
+ // Must be set before compiling any shaders to ensure consistency
+ // between the translated shaders and any necessary prequel.
+ void SetClampingStrategy(ShArrayIndexClampingStrategy clampingStrategy);
+
+ // Marks nodes in the tree that index arrays indirectly as
+ // requiring clamping.
+ void MarkIndirectArrayBoundsForClamping(TIntermNode* root);
+
+ // If necessary, output array clamp function source into the shader source.
+ void OutputClampingFunctionDefinition(TInfoSinkBase& out) const;
+
+ void Cleanup()
+ {
+ mArrayBoundsClampDefinitionNeeded = false;
+ }
+
+private:
+ bool GetArrayBoundsClampDefinitionNeeded() const { return mArrayBoundsClampDefinitionNeeded; }
+ void SetArrayBoundsClampDefinitionNeeded() { mArrayBoundsClampDefinitionNeeded = true; }
+
+ ShArrayIndexClampingStrategy mClampingStrategy;
+ bool mArrayBoundsClampDefinitionNeeded;
+};
+
+#endif // THIRD_PARTY_COMPILER_ARRAY_BOUNDS_CLAMPER_H_
diff --git a/src/third_party/compiler/LICENSE b/src/third_party/compiler/LICENSE
new file mode 100644
index 00000000..c2cb2125
--- /dev/null
+++ b/src/third_party/compiler/LICENSE
@@ -0,0 +1,22 @@
+Copyright (C) 2012 Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/third_party/compiler/README.angle b/src/third_party/compiler/README.angle
new file mode 100644
index 00000000..4fdf757e
--- /dev/null
+++ b/src/third_party/compiler/README.angle
@@ -0,0 +1,12 @@
+Name: ANGLE array bounds clamper from WebKit
+Short Name: WebKit
+URL: http://webkit.org
+Version: 0
+License: BSD
+Security Critical: yes
+
+Description:
+Implements clamping of array indexing expressions during shader translation.
+
+Local Modifications:
+None
diff --git a/src/third_party/murmurhash/LICENSE b/src/third_party/murmurhash/LICENSE
new file mode 100644
index 00000000..6a385f0f
--- /dev/null
+++ b/src/third_party/murmurhash/LICENSE
@@ -0,0 +1,2 @@
+// MurmurHash3 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code. \ No newline at end of file
diff --git a/src/third_party/murmurhash/MurmurHash3.cpp b/src/third_party/murmurhash/MurmurHash3.cpp
new file mode 100644
index 00000000..94a18a59
--- /dev/null
+++ b/src/third_party/murmurhash/MurmurHash3.cpp
@@ -0,0 +1,334 @@
+//-----------------------------------------------------------------------------
+// MurmurHash3 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code.
+
+// Note - The x86 and x64 versions do _not_ produce the same results, as the
+// algorithms are optimized for their respective platforms. You can still
+// compile and run any of them on any platform, but your performance with the
+// non-native version will be less than optimal.
+
+#include "MurmurHash3.h"
+
+//-----------------------------------------------------------------------------
+// Platform-specific functions and macros
+
+// Microsoft Visual Studio
+
+#if defined(_MSC_VER)
+
+#define FORCE_INLINE __forceinline
+
+#include <stdlib.h>
+
+#define ROTL32(x,y) _rotl(x,y)
+#define ROTL64(x,y) _rotl64(x,y)
+
+#define BIG_CONSTANT(x) (x)
+
+// Other compilers
+
+#else // defined(_MSC_VER)
+
+#define FORCE_INLINE __attribute__((always_inline))
+
+inline uint32_t rotl32 ( uint32_t x, int8_t r )
+{
+ return (x << r) | (x >> (32 - r));
+}
+
+inline uint64_t rotl64 ( uint64_t x, int8_t r )
+{
+ return (x << r) | (x >> (64 - r));
+}
+
+#define ROTL32(x,y) rotl32(x,y)
+#define ROTL64(x,y) rotl64(x,y)
+
+#define BIG_CONSTANT(x) (x##LLU)
+
+#endif // !defined(_MSC_VER)
+
+//-----------------------------------------------------------------------------
+// Block read - if your platform needs to do endian-swapping or can only
+// handle aligned reads, do the conversion here
+
+FORCE_INLINE uint32_t getblock ( const uint32_t * p, int i )
+{
+ return p[i];
+}
+
+FORCE_INLINE uint64_t getblock ( const uint64_t * p, int i )
+{
+ return p[i];
+}
+
+//-----------------------------------------------------------------------------
+// Finalization mix - force all bits of a hash block to avalanche
+
+FORCE_INLINE uint32_t fmix ( uint32_t h )
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+
+ return h;
+}
+
+//----------
+
+FORCE_INLINE uint64_t fmix ( uint64_t k )
+{
+ k ^= k >> 33;
+ k *= BIG_CONSTANT(0xff51afd7ed558ccd);
+ k ^= k >> 33;
+ k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
+ k ^= k >> 33;
+
+ return k;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_32 ( const void * key, int len,
+ uint32_t seed, void * out )
+{
+ const uint8_t * data = (const uint8_t*)key;
+ const int nblocks = len / 4;
+
+ uint32_t h1 = seed;
+
+ const uint32_t c1 = 0xcc9e2d51;
+ const uint32_t c2 = 0x1b873593;
+
+ //----------
+ // body
+
+ const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
+
+ for(int i = -nblocks; i; i++)
+ {
+ uint32_t k1 = getblock(blocks,i);
+
+ k1 *= c1;
+ k1 = ROTL32(k1,15);
+ k1 *= c2;
+
+ h1 ^= k1;
+ h1 = ROTL32(h1,13);
+ h1 = h1*5+0xe6546b64;
+ }
+
+ //----------
+ // tail
+
+ const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
+
+ uint32_t k1 = 0;
+
+ switch(len & 3)
+ {
+ case 3: k1 ^= tail[2] << 16;
+ case 2: k1 ^= tail[1] << 8;
+ case 1: k1 ^= tail[0];
+ k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+ };
+
+ //----------
+ // finalization
+
+ h1 ^= len;
+
+ h1 = fmix(h1);
+
+ *(uint32_t*)out = h1;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_128 ( const void * key, const int len,
+ uint32_t seed, void * out )
+{
+ const uint8_t * data = (const uint8_t*)key;
+ const int nblocks = len / 16;
+
+ uint32_t h1 = seed;
+ uint32_t h2 = seed;
+ uint32_t h3 = seed;
+ uint32_t h4 = seed;
+
+ const uint32_t c1 = 0x239b961b;
+ const uint32_t c2 = 0xab0e9789;
+ const uint32_t c3 = 0x38b34ae5;
+ const uint32_t c4 = 0xa1e38b93;
+
+ //----------
+ // body
+
+ const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
+
+ for(int i = -nblocks; i; i++)
+ {
+ uint32_t k1 = getblock(blocks,i*4+0);
+ uint32_t k2 = getblock(blocks,i*4+1);
+ uint32_t k3 = getblock(blocks,i*4+2);
+ uint32_t k4 = getblock(blocks,i*4+3);
+
+ k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+
+ h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
+
+ k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
+
+ h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
+
+ k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
+
+ h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
+
+ k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
+
+ h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
+ }
+
+ //----------
+ // tail
+
+ const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
+
+ uint32_t k1 = 0;
+ uint32_t k2 = 0;
+ uint32_t k3 = 0;
+ uint32_t k4 = 0;
+
+ switch(len & 15)
+ {
+ case 15: k4 ^= tail[14] << 16;
+ case 14: k4 ^= tail[13] << 8;
+ case 13: k4 ^= tail[12] << 0;
+ k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
+
+ case 12: k3 ^= tail[11] << 24;
+ case 11: k3 ^= tail[10] << 16;
+ case 10: k3 ^= tail[ 9] << 8;
+ case 9: k3 ^= tail[ 8] << 0;
+ k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
+
+ case 8: k2 ^= tail[ 7] << 24;
+ case 7: k2 ^= tail[ 6] << 16;
+ case 6: k2 ^= tail[ 5] << 8;
+ case 5: k2 ^= tail[ 4] << 0;
+ k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
+
+ case 4: k1 ^= tail[ 3] << 24;
+ case 3: k1 ^= tail[ 2] << 16;
+ case 2: k1 ^= tail[ 1] << 8;
+ case 1: k1 ^= tail[ 0] << 0;
+ k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+ };
+
+ //----------
+ // finalization
+
+ h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
+
+ h1 += h2; h1 += h3; h1 += h4;
+ h2 += h1; h3 += h1; h4 += h1;
+
+ h1 = fmix(h1);
+ h2 = fmix(h2);
+ h3 = fmix(h3);
+ h4 = fmix(h4);
+
+ h1 += h2; h1 += h3; h1 += h4;
+ h2 += h1; h3 += h1; h4 += h1;
+
+ ((uint32_t*)out)[0] = h1;
+ ((uint32_t*)out)[1] = h2;
+ ((uint32_t*)out)[2] = h3;
+ ((uint32_t*)out)[3] = h4;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x64_128 ( const void * key, const int len,
+ const uint32_t seed, void * out )
+{
+ const uint8_t * data = (const uint8_t*)key;
+ const int nblocks = len / 16;
+
+ uint64_t h1 = seed;
+ uint64_t h2 = seed;
+
+ const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
+ const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
+
+ //----------
+ // body
+
+ const uint64_t * blocks = (const uint64_t *)(data);
+
+ for(int i = 0; i < nblocks; i++)
+ {
+ uint64_t k1 = getblock(blocks,i*2+0);
+ uint64_t k2 = getblock(blocks,i*2+1);
+
+ k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
+
+ h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
+
+ k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
+
+ h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
+ }
+
+ //----------
+ // tail
+
+ const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
+
+ uint64_t k1 = 0;
+ uint64_t k2 = 0;
+
+ switch(len & 15)
+ {
+ case 15: k2 ^= uint64_t(tail[14]) << 48;
+ case 14: k2 ^= uint64_t(tail[13]) << 40;
+ case 13: k2 ^= uint64_t(tail[12]) << 32;
+ case 12: k2 ^= uint64_t(tail[11]) << 24;
+ case 11: k2 ^= uint64_t(tail[10]) << 16;
+ case 10: k2 ^= uint64_t(tail[ 9]) << 8;
+ case 9: k2 ^= uint64_t(tail[ 8]) << 0;
+ k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
+
+ case 8: k1 ^= uint64_t(tail[ 7]) << 56;
+ case 7: k1 ^= uint64_t(tail[ 6]) << 48;
+ case 6: k1 ^= uint64_t(tail[ 5]) << 40;
+ case 5: k1 ^= uint64_t(tail[ 4]) << 32;
+ case 4: k1 ^= uint64_t(tail[ 3]) << 24;
+ case 3: k1 ^= uint64_t(tail[ 2]) << 16;
+ case 2: k1 ^= uint64_t(tail[ 1]) << 8;
+ case 1: k1 ^= uint64_t(tail[ 0]) << 0;
+ k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
+ };
+
+ //----------
+ // finalization
+
+ h1 ^= len; h2 ^= len;
+
+ h1 += h2;
+ h2 += h1;
+
+ h1 = fmix(h1);
+ h2 = fmix(h2);
+
+ h1 += h2;
+ h2 += h1;
+
+ ((uint64_t*)out)[0] = h1;
+ ((uint64_t*)out)[1] = h2;
+}
+
+//-----------------------------------------------------------------------------
diff --git a/src/third_party/murmurhash/MurmurHash3.h b/src/third_party/murmurhash/MurmurHash3.h
new file mode 100644
index 00000000..3c6c78cd
--- /dev/null
+++ b/src/third_party/murmurhash/MurmurHash3.h
@@ -0,0 +1,37 @@
+//-----------------------------------------------------------------------------
+// MurmurHash3 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code.
+
+#ifndef _MURMURHASH3_H_
+#define _MURMURHASH3_H_
+
+//-----------------------------------------------------------------------------
+// Platform-specific functions and macros
+
+// Microsoft Visual Studio
+
+#if defined(_MSC_VER)
+
+typedef unsigned char uint8_t;
+typedef unsigned long uint32_t;
+typedef unsigned __int64 uint64_t;
+
+// Other compilers
+
+#else // defined(_MSC_VER)
+
+#include <stdint.h>
+
+#endif // !defined(_MSC_VER)
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out );
+
+void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out );
+
+void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out );
+
+//-----------------------------------------------------------------------------
+
+#endif // _MURMURHASH3_H_ \ No newline at end of file
diff --git a/src/translator_common.target.darwin-arm.mk b/src/translator_common.target.darwin-arm.mk
new file mode 100644
index 00000000..a0401336
--- /dev/null
+++ b/src/translator_common.target.darwin-arm.mk
@@ -0,0 +1,303 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_common_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/BuiltInFunctionEmulator.cpp \
+ third_party/angle_dx11/src/compiler/Compiler.cpp \
+ third_party/angle_dx11/src/compiler/debug.cpp \
+ third_party/angle_dx11/src/compiler/DetectCallDepth.cpp \
+ third_party/angle_dx11/src/compiler/Diagnostics.cpp \
+ third_party/angle_dx11/src/compiler/DirectiveHandler.cpp \
+ third_party/angle_dx11/src/compiler/ForLoopUnroll.cpp \
+ third_party/angle_dx11/src/compiler/glslang_lex.cpp \
+ third_party/angle_dx11/src/compiler/glslang_tab.cpp \
+ third_party/angle_dx11/src/compiler/InfoSink.cpp \
+ third_party/angle_dx11/src/compiler/Initialize.cpp \
+ third_party/angle_dx11/src/compiler/InitializeDll.cpp \
+ third_party/angle_dx11/src/compiler/InitializeParseContext.cpp \
+ third_party/angle_dx11/src/compiler/Intermediate.cpp \
+ third_party/angle_dx11/src/compiler/intermOut.cpp \
+ third_party/angle_dx11/src/compiler/IntermTraverse.cpp \
+ third_party/angle_dx11/src/compiler/MapLongVariableNames.cpp \
+ third_party/angle_dx11/src/compiler/parseConst.cpp \
+ third_party/angle_dx11/src/compiler/ParseHelper.cpp \
+ third_party/angle_dx11/src/compiler/PoolAlloc.cpp \
+ third_party/angle_dx11/src/compiler/QualifierAlive.cpp \
+ third_party/angle_dx11/src/compiler/RemoveTree.cpp \
+ third_party/angle_dx11/src/compiler/SymbolTable.cpp \
+ third_party/angle_dx11/src/compiler/Uniform.cpp \
+ third_party/angle_dx11/src/compiler/util.cpp \
+ third_party/angle_dx11/src/compiler/ValidateLimitations.cpp \
+ third_party/angle_dx11/src/compiler/VariableInfo.cpp \
+ third_party/angle_dx11/src/compiler/VariablePacker.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraph.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphBuilder.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphOutput.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphTraverse.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictFragmentShaderTiming.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictVertexShaderTiming.cpp \
+ third_party/angle_dx11/src/third_party/compiler/ArrayBoundsClamper.cpp \
+ third_party/angle_dx11/src/compiler/ossource_posix.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_common_gyp
+
+# Alias gyp target name.
+.PHONY: translator_common
+translator_common: third_party_angle_dx11_src_translator_common_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_common.target.darwin-mips.mk b/src/translator_common.target.darwin-mips.mk
new file mode 100644
index 00000000..ad1ed22a
--- /dev/null
+++ b/src/translator_common.target.darwin-mips.mk
@@ -0,0 +1,299 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_common_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/BuiltInFunctionEmulator.cpp \
+ third_party/angle_dx11/src/compiler/Compiler.cpp \
+ third_party/angle_dx11/src/compiler/debug.cpp \
+ third_party/angle_dx11/src/compiler/DetectCallDepth.cpp \
+ third_party/angle_dx11/src/compiler/Diagnostics.cpp \
+ third_party/angle_dx11/src/compiler/DirectiveHandler.cpp \
+ third_party/angle_dx11/src/compiler/ForLoopUnroll.cpp \
+ third_party/angle_dx11/src/compiler/glslang_lex.cpp \
+ third_party/angle_dx11/src/compiler/glslang_tab.cpp \
+ third_party/angle_dx11/src/compiler/InfoSink.cpp \
+ third_party/angle_dx11/src/compiler/Initialize.cpp \
+ third_party/angle_dx11/src/compiler/InitializeDll.cpp \
+ third_party/angle_dx11/src/compiler/InitializeParseContext.cpp \
+ third_party/angle_dx11/src/compiler/Intermediate.cpp \
+ third_party/angle_dx11/src/compiler/intermOut.cpp \
+ third_party/angle_dx11/src/compiler/IntermTraverse.cpp \
+ third_party/angle_dx11/src/compiler/MapLongVariableNames.cpp \
+ third_party/angle_dx11/src/compiler/parseConst.cpp \
+ third_party/angle_dx11/src/compiler/ParseHelper.cpp \
+ third_party/angle_dx11/src/compiler/PoolAlloc.cpp \
+ third_party/angle_dx11/src/compiler/QualifierAlive.cpp \
+ third_party/angle_dx11/src/compiler/RemoveTree.cpp \
+ third_party/angle_dx11/src/compiler/SymbolTable.cpp \
+ third_party/angle_dx11/src/compiler/Uniform.cpp \
+ third_party/angle_dx11/src/compiler/util.cpp \
+ third_party/angle_dx11/src/compiler/ValidateLimitations.cpp \
+ third_party/angle_dx11/src/compiler/VariableInfo.cpp \
+ third_party/angle_dx11/src/compiler/VariablePacker.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraph.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphBuilder.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphOutput.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphTraverse.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictFragmentShaderTiming.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictVertexShaderTiming.cpp \
+ third_party/angle_dx11/src/third_party/compiler/ArrayBoundsClamper.cpp \
+ third_party/angle_dx11/src/compiler/ossource_posix.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_common_gyp
+
+# Alias gyp target name.
+.PHONY: translator_common
+translator_common: third_party_angle_dx11_src_translator_common_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_common.target.darwin-x86.mk b/src/translator_common.target.darwin-x86.mk
new file mode 100644
index 00000000..23fddb04
--- /dev/null
+++ b/src/translator_common.target.darwin-x86.mk
@@ -0,0 +1,303 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_common_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/BuiltInFunctionEmulator.cpp \
+ third_party/angle_dx11/src/compiler/Compiler.cpp \
+ third_party/angle_dx11/src/compiler/debug.cpp \
+ third_party/angle_dx11/src/compiler/DetectCallDepth.cpp \
+ third_party/angle_dx11/src/compiler/Diagnostics.cpp \
+ third_party/angle_dx11/src/compiler/DirectiveHandler.cpp \
+ third_party/angle_dx11/src/compiler/ForLoopUnroll.cpp \
+ third_party/angle_dx11/src/compiler/glslang_lex.cpp \
+ third_party/angle_dx11/src/compiler/glslang_tab.cpp \
+ third_party/angle_dx11/src/compiler/InfoSink.cpp \
+ third_party/angle_dx11/src/compiler/Initialize.cpp \
+ third_party/angle_dx11/src/compiler/InitializeDll.cpp \
+ third_party/angle_dx11/src/compiler/InitializeParseContext.cpp \
+ third_party/angle_dx11/src/compiler/Intermediate.cpp \
+ third_party/angle_dx11/src/compiler/intermOut.cpp \
+ third_party/angle_dx11/src/compiler/IntermTraverse.cpp \
+ third_party/angle_dx11/src/compiler/MapLongVariableNames.cpp \
+ third_party/angle_dx11/src/compiler/parseConst.cpp \
+ third_party/angle_dx11/src/compiler/ParseHelper.cpp \
+ third_party/angle_dx11/src/compiler/PoolAlloc.cpp \
+ third_party/angle_dx11/src/compiler/QualifierAlive.cpp \
+ third_party/angle_dx11/src/compiler/RemoveTree.cpp \
+ third_party/angle_dx11/src/compiler/SymbolTable.cpp \
+ third_party/angle_dx11/src/compiler/Uniform.cpp \
+ third_party/angle_dx11/src/compiler/util.cpp \
+ third_party/angle_dx11/src/compiler/ValidateLimitations.cpp \
+ third_party/angle_dx11/src/compiler/VariableInfo.cpp \
+ third_party/angle_dx11/src/compiler/VariablePacker.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraph.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphBuilder.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphOutput.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphTraverse.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictFragmentShaderTiming.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictVertexShaderTiming.cpp \
+ third_party/angle_dx11/src/third_party/compiler/ArrayBoundsClamper.cpp \
+ third_party/angle_dx11/src/compiler/ossource_posix.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer \
+ -fno-unwind-tables \
+ -fno-asynchronous-unwind-tables
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_common_gyp
+
+# Alias gyp target name.
+.PHONY: translator_common
+translator_common: third_party_angle_dx11_src_translator_common_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_common.target.linux-arm.mk b/src/translator_common.target.linux-arm.mk
new file mode 100644
index 00000000..a0401336
--- /dev/null
+++ b/src/translator_common.target.linux-arm.mk
@@ -0,0 +1,303 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_common_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/BuiltInFunctionEmulator.cpp \
+ third_party/angle_dx11/src/compiler/Compiler.cpp \
+ third_party/angle_dx11/src/compiler/debug.cpp \
+ third_party/angle_dx11/src/compiler/DetectCallDepth.cpp \
+ third_party/angle_dx11/src/compiler/Diagnostics.cpp \
+ third_party/angle_dx11/src/compiler/DirectiveHandler.cpp \
+ third_party/angle_dx11/src/compiler/ForLoopUnroll.cpp \
+ third_party/angle_dx11/src/compiler/glslang_lex.cpp \
+ third_party/angle_dx11/src/compiler/glslang_tab.cpp \
+ third_party/angle_dx11/src/compiler/InfoSink.cpp \
+ third_party/angle_dx11/src/compiler/Initialize.cpp \
+ third_party/angle_dx11/src/compiler/InitializeDll.cpp \
+ third_party/angle_dx11/src/compiler/InitializeParseContext.cpp \
+ third_party/angle_dx11/src/compiler/Intermediate.cpp \
+ third_party/angle_dx11/src/compiler/intermOut.cpp \
+ third_party/angle_dx11/src/compiler/IntermTraverse.cpp \
+ third_party/angle_dx11/src/compiler/MapLongVariableNames.cpp \
+ third_party/angle_dx11/src/compiler/parseConst.cpp \
+ third_party/angle_dx11/src/compiler/ParseHelper.cpp \
+ third_party/angle_dx11/src/compiler/PoolAlloc.cpp \
+ third_party/angle_dx11/src/compiler/QualifierAlive.cpp \
+ third_party/angle_dx11/src/compiler/RemoveTree.cpp \
+ third_party/angle_dx11/src/compiler/SymbolTable.cpp \
+ third_party/angle_dx11/src/compiler/Uniform.cpp \
+ third_party/angle_dx11/src/compiler/util.cpp \
+ third_party/angle_dx11/src/compiler/ValidateLimitations.cpp \
+ third_party/angle_dx11/src/compiler/VariableInfo.cpp \
+ third_party/angle_dx11/src/compiler/VariablePacker.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraph.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphBuilder.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphOutput.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphTraverse.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictFragmentShaderTiming.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictVertexShaderTiming.cpp \
+ third_party/angle_dx11/src/third_party/compiler/ArrayBoundsClamper.cpp \
+ third_party/angle_dx11/src/compiler/ossource_posix.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_common_gyp
+
+# Alias gyp target name.
+.PHONY: translator_common
+translator_common: third_party_angle_dx11_src_translator_common_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_common.target.linux-mips.mk b/src/translator_common.target.linux-mips.mk
new file mode 100644
index 00000000..ad1ed22a
--- /dev/null
+++ b/src/translator_common.target.linux-mips.mk
@@ -0,0 +1,299 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_common_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/BuiltInFunctionEmulator.cpp \
+ third_party/angle_dx11/src/compiler/Compiler.cpp \
+ third_party/angle_dx11/src/compiler/debug.cpp \
+ third_party/angle_dx11/src/compiler/DetectCallDepth.cpp \
+ third_party/angle_dx11/src/compiler/Diagnostics.cpp \
+ third_party/angle_dx11/src/compiler/DirectiveHandler.cpp \
+ third_party/angle_dx11/src/compiler/ForLoopUnroll.cpp \
+ third_party/angle_dx11/src/compiler/glslang_lex.cpp \
+ third_party/angle_dx11/src/compiler/glslang_tab.cpp \
+ third_party/angle_dx11/src/compiler/InfoSink.cpp \
+ third_party/angle_dx11/src/compiler/Initialize.cpp \
+ third_party/angle_dx11/src/compiler/InitializeDll.cpp \
+ third_party/angle_dx11/src/compiler/InitializeParseContext.cpp \
+ third_party/angle_dx11/src/compiler/Intermediate.cpp \
+ third_party/angle_dx11/src/compiler/intermOut.cpp \
+ third_party/angle_dx11/src/compiler/IntermTraverse.cpp \
+ third_party/angle_dx11/src/compiler/MapLongVariableNames.cpp \
+ third_party/angle_dx11/src/compiler/parseConst.cpp \
+ third_party/angle_dx11/src/compiler/ParseHelper.cpp \
+ third_party/angle_dx11/src/compiler/PoolAlloc.cpp \
+ third_party/angle_dx11/src/compiler/QualifierAlive.cpp \
+ third_party/angle_dx11/src/compiler/RemoveTree.cpp \
+ third_party/angle_dx11/src/compiler/SymbolTable.cpp \
+ third_party/angle_dx11/src/compiler/Uniform.cpp \
+ third_party/angle_dx11/src/compiler/util.cpp \
+ third_party/angle_dx11/src/compiler/ValidateLimitations.cpp \
+ third_party/angle_dx11/src/compiler/VariableInfo.cpp \
+ third_party/angle_dx11/src/compiler/VariablePacker.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraph.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphBuilder.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphOutput.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphTraverse.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictFragmentShaderTiming.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictVertexShaderTiming.cpp \
+ third_party/angle_dx11/src/third_party/compiler/ArrayBoundsClamper.cpp \
+ third_party/angle_dx11/src/compiler/ossource_posix.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_common_gyp
+
+# Alias gyp target name.
+.PHONY: translator_common
+translator_common: third_party_angle_dx11_src_translator_common_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_common.target.linux-x86.mk b/src/translator_common.target.linux-x86.mk
new file mode 100644
index 00000000..23fddb04
--- /dev/null
+++ b/src/translator_common.target.linux-x86.mk
@@ -0,0 +1,303 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_common_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/BuiltInFunctionEmulator.cpp \
+ third_party/angle_dx11/src/compiler/Compiler.cpp \
+ third_party/angle_dx11/src/compiler/debug.cpp \
+ third_party/angle_dx11/src/compiler/DetectCallDepth.cpp \
+ third_party/angle_dx11/src/compiler/Diagnostics.cpp \
+ third_party/angle_dx11/src/compiler/DirectiveHandler.cpp \
+ third_party/angle_dx11/src/compiler/ForLoopUnroll.cpp \
+ third_party/angle_dx11/src/compiler/glslang_lex.cpp \
+ third_party/angle_dx11/src/compiler/glslang_tab.cpp \
+ third_party/angle_dx11/src/compiler/InfoSink.cpp \
+ third_party/angle_dx11/src/compiler/Initialize.cpp \
+ third_party/angle_dx11/src/compiler/InitializeDll.cpp \
+ third_party/angle_dx11/src/compiler/InitializeParseContext.cpp \
+ third_party/angle_dx11/src/compiler/Intermediate.cpp \
+ third_party/angle_dx11/src/compiler/intermOut.cpp \
+ third_party/angle_dx11/src/compiler/IntermTraverse.cpp \
+ third_party/angle_dx11/src/compiler/MapLongVariableNames.cpp \
+ third_party/angle_dx11/src/compiler/parseConst.cpp \
+ third_party/angle_dx11/src/compiler/ParseHelper.cpp \
+ third_party/angle_dx11/src/compiler/PoolAlloc.cpp \
+ third_party/angle_dx11/src/compiler/QualifierAlive.cpp \
+ third_party/angle_dx11/src/compiler/RemoveTree.cpp \
+ third_party/angle_dx11/src/compiler/SymbolTable.cpp \
+ third_party/angle_dx11/src/compiler/Uniform.cpp \
+ third_party/angle_dx11/src/compiler/util.cpp \
+ third_party/angle_dx11/src/compiler/ValidateLimitations.cpp \
+ third_party/angle_dx11/src/compiler/VariableInfo.cpp \
+ third_party/angle_dx11/src/compiler/VariablePacker.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraph.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphBuilder.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphOutput.cpp \
+ third_party/angle_dx11/src/compiler/depgraph/DependencyGraphTraverse.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictFragmentShaderTiming.cpp \
+ third_party/angle_dx11/src/compiler/timing/RestrictVertexShaderTiming.cpp \
+ third_party/angle_dx11/src/third_party/compiler/ArrayBoundsClamper.cpp \
+ third_party/angle_dx11/src/compiler/ossource_posix.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer \
+ -fno-unwind-tables \
+ -fno-asynchronous-unwind-tables
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_common_gyp
+
+# Alias gyp target name.
+.PHONY: translator_common
+translator_common: third_party_angle_dx11_src_translator_common_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_glsl.target.darwin-arm.mk b/src/translator_glsl.target.darwin-arm.mk
new file mode 100644
index 00000000..7c1cf91c
--- /dev/null
+++ b/src/translator_glsl.target.darwin-arm.mk
@@ -0,0 +1,275 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_glsl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/CodeGenGLSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputESSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSLBase.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSL.cpp \
+ third_party/angle_dx11/src/compiler/ShaderLang.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorESSL.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorGLSL.cpp \
+ third_party/angle_dx11/src/compiler/VersionGLSL.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_glsl_gyp
+
+# Alias gyp target name.
+.PHONY: translator_glsl
+translator_glsl: third_party_angle_dx11_src_translator_glsl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_glsl.target.darwin-mips.mk b/src/translator_glsl.target.darwin-mips.mk
new file mode 100644
index 00000000..b0e8e615
--- /dev/null
+++ b/src/translator_glsl.target.darwin-mips.mk
@@ -0,0 +1,271 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_glsl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/CodeGenGLSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputESSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSLBase.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSL.cpp \
+ third_party/angle_dx11/src/compiler/ShaderLang.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorESSL.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorGLSL.cpp \
+ third_party/angle_dx11/src/compiler/VersionGLSL.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_glsl_gyp
+
+# Alias gyp target name.
+.PHONY: translator_glsl
+translator_glsl: third_party_angle_dx11_src_translator_glsl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_glsl.target.darwin-x86.mk b/src/translator_glsl.target.darwin-x86.mk
new file mode 100644
index 00000000..84defe27
--- /dev/null
+++ b/src/translator_glsl.target.darwin-x86.mk
@@ -0,0 +1,275 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_glsl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/CodeGenGLSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputESSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSLBase.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSL.cpp \
+ third_party/angle_dx11/src/compiler/ShaderLang.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorESSL.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorGLSL.cpp \
+ third_party/angle_dx11/src/compiler/VersionGLSL.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer \
+ -fno-unwind-tables \
+ -fno-asynchronous-unwind-tables
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_glsl_gyp
+
+# Alias gyp target name.
+.PHONY: translator_glsl
+translator_glsl: third_party_angle_dx11_src_translator_glsl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_glsl.target.linux-arm.mk b/src/translator_glsl.target.linux-arm.mk
new file mode 100644
index 00000000..7c1cf91c
--- /dev/null
+++ b/src/translator_glsl.target.linux-arm.mk
@@ -0,0 +1,275 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_glsl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/CodeGenGLSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputESSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSLBase.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSL.cpp \
+ third_party/angle_dx11/src/compiler/ShaderLang.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorESSL.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorGLSL.cpp \
+ third_party/angle_dx11/src/compiler/VersionGLSL.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -fno-tree-sra \
+ -fuse-ld=gold \
+ -Wno-psabi \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-abi \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -Wl,-z,relro \
+ -Wl,-z,now \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--icf=safe \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_glsl_gyp
+
+# Alias gyp target name.
+.PHONY: translator_glsl
+translator_glsl: third_party_angle_dx11_src_translator_glsl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_glsl.target.linux-mips.mk b/src/translator_glsl.target.linux-mips.mk
new file mode 100644
index 00000000..b0e8e615
--- /dev/null
+++ b/src/translator_glsl.target.linux-mips.mk
@@ -0,0 +1,271 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_glsl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/CodeGenGLSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputESSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSLBase.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSL.cpp \
+ third_party/angle_dx11/src/compiler/ShaderLang.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorESSL.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorGLSL.cpp \
+ third_party/angle_dx11/src/compiler/VersionGLSL.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ -fstack-protector \
+ --param=ssp-buffer-size=4 \
+ \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -EL \
+ -mhard-float \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fstack-protector \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-uninitialized \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -EL \
+ -Wl,--no-keep-memory \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_glsl_gyp
+
+# Alias gyp target name.
+.PHONY: translator_glsl
+translator_glsl: third_party_angle_dx11_src_translator_glsl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/translator_glsl.target.linux-x86.mk b/src/translator_glsl.target.linux-x86.mk
new file mode 100644
index 00000000..84defe27
--- /dev/null
+++ b/src/translator_glsl.target.linux-x86.mk
@@ -0,0 +1,275 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_angle_dx11_src_translator_glsl_gyp
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+gyp_intermediate_dir := $(call local-intermediates-dir)
+gyp_shared_intermediate_dir := $(call intermediates-dir-for,GYP,shared)
+
+# Make sure our deps are built first.
+GYP_TARGET_DEPENDENCIES :=
+
+GYP_GENERATED_OUTPUTS :=
+
+# Make sure our deps and generated files are built first.
+LOCAL_ADDITIONAL_DEPENDENCIES := $(GYP_TARGET_DEPENDENCIES) $(GYP_GENERATED_OUTPUTS)
+
+LOCAL_GENERATED_SOURCES :=
+
+GYP_COPIED_SOURCE_ORIGIN_DIRS :=
+
+LOCAL_SRC_FILES := \
+ third_party/angle_dx11/src/compiler/CodeGenGLSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputESSL.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSLBase.cpp \
+ third_party/angle_dx11/src/compiler/OutputGLSL.cpp \
+ third_party/angle_dx11/src/compiler/ShaderLang.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorESSL.cpp \
+ third_party/angle_dx11/src/compiler/TranslatorGLSL.cpp \
+ third_party/angle_dx11/src/compiler/VersionGLSL.cpp
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -g \
+ -fomit-frame-pointer \
+ -fdata-sections \
+ -ffunction-sections
+
+MY_DEFS_Debug := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+ '-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+ '-D_DEBUG'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+ --param=ssp-buffer-size=4 \
+ -fno-exceptions \
+ -fno-strict-aliasing \
+ -Wno-unused-parameter \
+ -Wno-missing-field-initializers \
+ -fvisibility=hidden \
+ -pipe \
+ -fPIC \
+ -Wno-format \
+ -m32 \
+ -mmmx \
+ -march=pentium4 \
+ -msse2 \
+ -mfpmath=sse \
+ -fuse-ld=gold \
+ -ffunction-sections \
+ -funwind-tables \
+ -g \
+ -fno-short-enums \
+ -finline-limit=64 \
+ -Wa,--noexecstack \
+ -U_FORTIFY_SOURCE \
+ -Wno-extra \
+ -Wno-ignored-qualifiers \
+ -Wno-type-limits \
+ -Wno-address \
+ -Wno-format-security \
+ -Wno-return-type \
+ -Wno-sequence-point \
+ -fno-stack-protector \
+ -Os \
+ -fno-ident \
+ -fdata-sections \
+ -ffunction-sections \
+ -fomit-frame-pointer \
+ -fno-unwind-tables \
+ -fno-asynchronous-unwind-tables
+
+MY_DEFS_Release := \
+ '-DANGLE_DX11' \
+ '-DANGLE_DISABLE_TRACE' \
+ '-DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL1' \
+ '-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DNO_TCMALLOC' \
+ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+ '-DDISABLE_NACL' \
+ '-DCHROMIUM_BUILD' \
+ '-DUSE_LIBJPEG_TURBO=1' \
+ '-DUSE_PROPRIETARY_CODECS' \
+ '-DENABLE_CONFIGURATION_POLICY' \
+ '-DLOGGING_IS_OFFICIAL_BUILD=1' \
+ '-DTRACING_IS_OFFICIAL_BUILD=1' \
+ '-DENABLE_GPU=1' \
+ '-DUSE_OPENSSL=1' \
+ '-DENABLE_EGLIMAGE=1' \
+ '-DENABLE_PRINTING=1' \
+ '-DCOMPILER_IMPLEMENTATION' \
+ '-DANDROID' \
+ '-D__GNU_SOURCE=1' \
+ '-DUSE_STLPORT=1' \
+ '-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+ '-DCHROME_BUILD_ID=""' \
+ '-DNDEBUG' \
+ '-DNVALGRIND' \
+ '-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+ $(LOCAL_PATH)/third_party/angle_dx11/src \
+ $(LOCAL_PATH)/third_party/angle_dx11/include \
+ $(PWD)/frameworks/wilhelm/include \
+ $(PWD)/bionic \
+ $(PWD)/external/stlport/stlport
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+ -fno-rtti \
+ -fno-threadsafe-statics \
+ -fvisibility-inlines-hidden \
+ -Wno-deprecated \
+ -Wno-error=c++0x-compat \
+ -Wno-non-virtual-dtor \
+ -Wno-sign-promo \
+ -Wno-non-virtual-dtor
+
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,--fatal-warnings \
+ -Wl,--gc-sections \
+ -Wl,--warn-shared-textrel \
+ -Wl,-O1 \
+ -Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+ -Wl,-z,now \
+ -Wl,-z,relro \
+ -Wl,-z,noexecstack \
+ -fPIC \
+ -m32 \
+ -fuse-ld=gold \
+ -nostdlib \
+ -Wl,--no-undefined \
+ -Wl,--exclude-libs=ALL \
+ -Wl,-O1 \
+ -Wl,--as-needed \
+ -Wl,--gc-sections \
+ -Wl,--fatal-warnings \
+ -Wl,--warn-shared-textrel
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+ libstlport \
+ libdl
+
+# Add target alias to "gyp_all_modules" target.
+.PHONY: gyp_all_modules
+gyp_all_modules: third_party_angle_dx11_src_translator_glsl_gyp
+
+# Alias gyp target name.
+.PHONY: translator_glsl
+translator_glsl: third_party_angle_dx11_src_translator_glsl_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/tests/build_tests.gyp b/tests/build_tests.gyp
new file mode 100644
index 00000000..c80a4444
--- /dev/null
+++ b/tests/build_tests.gyp
@@ -0,0 +1,93 @@
+# Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'gtest',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../third_party/googletest',
+ '../third_party/googletest/include',
+ ],
+ 'sources': [
+ '../third_party/googletest/src/gtest-all.cc',
+ ],
+ },
+ {
+ 'target_name': 'gmock',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../third_party/googlemock',
+ '../third_party/googlemock/include',
+ '../third_party/googletest/include',
+ ],
+ 'sources': [
+ '../third_party/googlemock/src/gmock-all.cc',
+ ],
+ },
+ {
+ 'target_name': 'preprocessor_tests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../src/build_angle.gyp:preprocessor',
+ 'gtest',
+ 'gmock',
+ ],
+ 'include_dirs': [
+ '../src/compiler/preprocessor',
+ '../third_party/googletest/include',
+ '../third_party/googlemock/include',
+ ],
+ 'sources': [
+ '../third_party/googlemock/src/gmock_main.cc',
+ 'preprocessor_tests/char_test.cpp',
+ 'preprocessor_tests/comment_test.cpp',
+ 'preprocessor_tests/define_test.cpp',
+ 'preprocessor_tests/error_test.cpp',
+ 'preprocessor_tests/extension_test.cpp',
+ 'preprocessor_tests/identifier_test.cpp',
+ 'preprocessor_tests/if_test.cpp',
+ 'preprocessor_tests/input_test.cpp',
+ 'preprocessor_tests/location_test.cpp',
+ 'preprocessor_tests/MockDiagnostics.h',
+ 'preprocessor_tests/MockDirectiveHandler.h',
+ 'preprocessor_tests/number_test.cpp',
+ 'preprocessor_tests/operator_test.cpp',
+ 'preprocessor_tests/pragma_test.cpp',
+ 'preprocessor_tests/PreprocessorTest.cpp',
+ 'preprocessor_tests/PreprocessorTest.h',
+ 'preprocessor_tests/space_test.cpp',
+ 'preprocessor_tests/token_test.cpp',
+ 'preprocessor_tests/version_test.cpp',
+ ],
+ },
+ {
+ 'target_name': 'compiler_tests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../src/build_angle.gyp:translator_glsl',
+ 'gtest',
+ 'gmock',
+ ],
+ 'include_dirs': [
+ '../include',
+ '../src',
+ '../third_party/googletest/include',
+ '../third_party/googlemock/include',
+ ],
+ 'sources': [
+ '../third_party/googlemock/src/gmock_main.cc',
+ 'compiler_tests/ExpressionLimit_test.cpp',
+ 'compiler_tests/VariablePacker_test.cpp',
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/tests/compiler_tests/ExpressionLimit_test.cpp b/tests/compiler_tests/ExpressionLimit_test.cpp
new file mode 100644
index 00000000..3af099de
--- /dev/null
+++ b/tests/compiler_tests/ExpressionLimit_test.cpp
@@ -0,0 +1,512 @@
+//
+// 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.
+//
+#include <sstream>
+#include <string>
+#include <vector>
+#include "GLSLANG/ShaderLang.h"
+#include "gtest/gtest.h"
+
+#define SHADER(Src) #Src
+
+class ExpressionLimitTest : public testing::Test {
+protected:
+ static const int kMaxExpressionComplexity = 16;
+ static const int kMaxCallStackDepth = 16;
+ static const char* kExpressionTooComplex;
+ static const char* kCallStackTooDeep;
+ static const char* kHasRecursion;
+
+ virtual void SetUp()
+ {
+ memset(&resources, 0, sizeof(resources));
+
+ ASSERT_TRUE(ShInitialize() != 0) << "Could not ShInitialize";
+
+ GenerateResources(&resources);
+ }
+
+ virtual void TearDown()
+ {
+ ASSERT_TRUE(ShFinalize() != 0);
+ }
+
+ // Set up the per compile resources
+ void GenerateResources(ShBuiltInResources* resources)
+ {
+ ShInitBuiltInResources(resources);
+
+ resources->MaxVertexAttribs = 8;
+ resources->MaxVertexUniformVectors = 128;
+ resources->MaxVaryingVectors = 8;
+ resources->MaxVertexTextureImageUnits = 0;
+ resources->MaxCombinedTextureImageUnits = 8;
+ resources->MaxTextureImageUnits = 8;
+ resources->MaxFragmentUniformVectors = 16;
+ resources->MaxDrawBuffers = 1;
+
+ resources->OES_standard_derivatives = 0;
+ resources->OES_EGL_image_external = 0;
+
+ resources->MaxExpressionComplexity = kMaxExpressionComplexity;
+ resources->MaxCallStackDepth = kMaxCallStackDepth;
+ }
+
+ void GenerateLongExpression(int length, std::stringstream* ss)
+ {
+ for (int ii = 0; ii < length; ++ii) {
+ *ss << "+ vec4(" << ii << ")";
+ }
+ }
+
+ std::string GenerateShaderWithLongExpression(int length)
+ {
+ static const char* shaderStart = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+ void main()
+ {
+ gl_FragColor = u_color
+ );
+
+ std::stringstream ss;
+ ss << shaderStart;
+ GenerateLongExpression(length, &ss);
+ ss << "; }";
+
+ return ss.str();
+ }
+
+ std::string GenerateShaderWithUnusedLongExpression(int length)
+ {
+ static const char* shaderStart = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+ void main()
+ {
+ gl_FragColor = u_color;
+ }
+ vec4 someFunction() {
+ return u_color
+ );
+
+ std::stringstream ss;
+
+ ss << shaderStart;
+ GenerateLongExpression(length, &ss);
+ ss << "; }";
+
+ return ss.str();
+ }
+
+ void GenerateDeepFunctionStack(int length, std::stringstream* ss)
+ {
+ static const char* shaderStart = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+ vec4 function0() {
+ return u_color;
+ }
+ );
+
+ *ss << shaderStart;
+ for (int ii = 0; ii < length; ++ii) {
+ *ss << "vec4 function" << (ii + 1) << "() {\n"
+ << " return function" << ii << "();\n"
+ << "}\n";
+ }
+ }
+
+ std::string GenerateShaderWithDeepFunctionStack(int length)
+ {
+ std::stringstream ss;
+
+ GenerateDeepFunctionStack(length, &ss);
+
+ ss << "void main() {\n"
+ << " gl_FragColor = function" << length << "();\n"
+ << "}";
+
+ return ss.str();
+ }
+
+ std::string GenerateShaderWithUnusedDeepFunctionStack(int length)
+ {
+ std::stringstream ss;
+
+ GenerateDeepFunctionStack(length, &ss);
+
+ ss << "void main() {\n"
+ << " gl_FragColor = vec4(0,0,0,0);\n"
+ << "}";
+
+
+ return ss.str();
+ }
+
+ // Compiles a shader and if there's an error checks for a specific
+ // substring in the error log. This way we know the error is specific
+ // to the issue we are testing.
+ bool CheckShaderCompilation(ShHandle compiler,
+ const char* source,
+ int compileOptions,
+ const char* expected_error) {
+ bool success = ShCompile(compiler, &source, 1, compileOptions);
+ if (success) {
+ success = !expected_error;
+ } else {
+ size_t bufferLen = 0;
+ ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &bufferLen);
+ char* buffer(new char [bufferLen]);
+ ShGetInfoLog(compiler, buffer);
+ std::string log(buffer, buffer + bufferLen);
+ delete [] buffer;
+ if (expected_error)
+ success = log.find(expected_error) != std::string::npos;
+
+ EXPECT_TRUE(success) << log << "\n----shader----\n" << source;
+ }
+ return success;
+ }
+
+ ShBuiltInResources resources;
+};
+
+const char* ExpressionLimitTest::kExpressionTooComplex =
+ "Expression too complex";
+const char* ExpressionLimitTest::kCallStackTooDeep =
+ "call stack too deep";
+const char* ExpressionLimitTest::kHasRecursion =
+ "Function recursion detected";
+
+TEST_F(ExpressionLimitTest, ExpressionComplexity)
+{
+ ShShaderSpec spec = SH_WEBGL_SPEC;
+ ShShaderOutput output = SH_ESSL_OUTPUT;
+ ShHandle vertexCompiler = ShConstructCompiler(
+ SH_FRAGMENT_SHADER, spec, output, &resources);
+ int compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
+
+ // Test expression under the limit passes.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithLongExpression(
+ kMaxExpressionComplexity - 10).c_str(),
+ compileOptions, NULL));
+ // Test expression over the limit fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithLongExpression(
+ kMaxExpressionComplexity + 10).c_str(),
+ compileOptions, kExpressionTooComplex));
+ // Test expression over the limit without a limit does not fail.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithLongExpression(
+ kMaxExpressionComplexity + 10).c_str(),
+ compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL));
+}
+
+TEST_F(ExpressionLimitTest, UnusedExpressionComplexity)
+{
+ ShShaderSpec spec = SH_WEBGL_SPEC;
+ ShShaderOutput output = SH_ESSL_OUTPUT;
+ ShHandle vertexCompiler = ShConstructCompiler(
+ SH_FRAGMENT_SHADER, spec, output, &resources);
+ int compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
+
+ // Test expression under the limit passes.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithUnusedLongExpression(
+ kMaxExpressionComplexity - 10).c_str(),
+ compileOptions, NULL));
+ // Test expression over the limit fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithUnusedLongExpression(
+ kMaxExpressionComplexity + 10).c_str(),
+ compileOptions, kExpressionTooComplex));
+ // Test expression over the limit without a limit does not fail.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithUnusedLongExpression(
+ kMaxExpressionComplexity + 10).c_str(),
+ compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL));
+}
+
+TEST_F(ExpressionLimitTest, CallStackDepth)
+{
+ ShShaderSpec spec = SH_WEBGL_SPEC;
+ ShShaderOutput output = SH_ESSL_OUTPUT;
+ ShHandle vertexCompiler = ShConstructCompiler(
+ SH_FRAGMENT_SHADER, spec, output, &resources);
+ int compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
+
+ // Test call stack under the limit passes.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithDeepFunctionStack(
+ kMaxCallStackDepth - 10).c_str(),
+ compileOptions, NULL));
+ // Test call stack over the limit fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithDeepFunctionStack(
+ kMaxCallStackDepth + 10).c_str(),
+ compileOptions, kCallStackTooDeep));
+ // Test call stack over the limit without limit does not fail.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithDeepFunctionStack(
+ kMaxCallStackDepth + 10).c_str(),
+ compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL));
+}
+
+TEST_F(ExpressionLimitTest, UnusedCallStackDepth)
+{
+ ShShaderSpec spec = SH_WEBGL_SPEC;
+ ShShaderOutput output = SH_ESSL_OUTPUT;
+ ShHandle vertexCompiler = ShConstructCompiler(
+ SH_FRAGMENT_SHADER, spec, output, &resources);
+ int compileOptions = SH_LIMIT_CALL_STACK_DEPTH;
+
+ // Test call stack under the limit passes.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithUnusedDeepFunctionStack(
+ kMaxCallStackDepth - 10).c_str(),
+ compileOptions, NULL));
+ // Test call stack over the limit fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithUnusedDeepFunctionStack(
+ kMaxCallStackDepth + 10).c_str(),
+ compileOptions, kCallStackTooDeep));
+ // Test call stack over the limit without limit does not fail.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler,
+ GenerateShaderWithUnusedDeepFunctionStack(
+ kMaxCallStackDepth + 10).c_str(),
+ compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL));
+}
+
+TEST_F(ExpressionLimitTest, Recursion)
+{
+ ShShaderSpec spec = SH_WEBGL_SPEC;
+ ShShaderOutput output = SH_ESSL_OUTPUT;
+ ShHandle vertexCompiler = ShConstructCompiler(
+ SH_FRAGMENT_SHADER, spec, output, &resources);
+ int compileOptions = 0;
+
+ static const char* shaderWithRecursion0 = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+ vec4 someFunc() {
+ return someFunc();
+ }
+
+ void main() {
+ gl_FragColor = u_color * someFunc();
+ }
+ );
+
+ static const char* shaderWithRecursion1 = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+
+ vec4 someFunc();
+
+ vec4 someFunc1() {
+ return someFunc();
+ }
+
+ vec4 someFunc() {
+ return someFunc1();
+ }
+
+ void main() {
+ gl_FragColor = u_color * someFunc();
+ }
+ );
+
+ static const char* shaderWithRecursion2 = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+ vec4 someFunc() {
+ if (u_color.x > 0.5) {
+ return someFunc();
+ } else {
+ return vec4(1);
+ }
+ }
+
+ void main() {
+ gl_FragColor = someFunc();
+ }
+ );
+
+ static const char* shaderWithRecursion3 = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+ vec4 someFunc() {
+ if (u_color.x > 0.5) {
+ return vec4(1);
+ } else {
+ return someFunc();
+ }
+ }
+
+ void main() {
+ gl_FragColor = someFunc();
+ }
+ );
+
+ static const char* shaderWithRecursion4 = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+ vec4 someFunc() {
+ return (u_color.x > 0.5) ? vec4(1) : someFunc();
+ }
+
+ void main() {
+ gl_FragColor = someFunc();
+ }
+ );
+
+ static const char* shaderWithRecursion5 = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+ vec4 someFunc() {
+ return (u_color.x > 0.5) ? someFunc() : vec4(1);
+ }
+
+ void main() {
+ gl_FragColor = someFunc();
+ }
+ );
+
+ static const char* shaderWithRecursion6 = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+ vec4 someFunc() {
+ return someFunc();
+ }
+
+ void main() {
+ gl_FragColor = u_color;
+ }
+ );
+
+ static const char* shaderWithNoRecursion = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+
+ vec3 rgb(int r, int g, int b) {
+ return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0);
+ }
+
+ // these external calls used to incorrectly trigger
+ // recursion detection.
+ vec3 hairColor0 = rgb(151, 200, 234);
+ vec3 faceColor2 = rgb(183, 148, 133);
+
+ void main() {
+ gl_FragColor = u_color + vec4(hairColor0 + faceColor2, 0);
+ }
+ );
+
+ static const char* shaderWithRecursion7 = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+
+ vec4 function2() {
+ return u_color;
+ }
+
+ vec4 function1() {
+ vec4 a = function2();
+ vec4 b = function1();
+ return a + b;
+ }
+
+ void main() {
+ gl_FragColor = function1();
+ }
+ );
+
+ static const char* shaderWithRecursion8 = SHADER(
+ precision mediump float;
+ uniform vec4 u_color;
+
+ vec4 function1();
+
+ vec4 function3() {
+ return function1();
+ }
+
+ vec4 function2() {
+ return function3();
+ }
+
+ vec4 function1() {
+ return function2();
+ }
+
+ void main() {
+ gl_FragColor = function1();
+ }
+ );
+
+ // Check simple recursions fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion0,
+ compileOptions, kHasRecursion));
+ // Check simple recursions fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion1,
+ compileOptions, kHasRecursion));
+ // Check if recursions fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion2,
+ compileOptions, kHasRecursion));
+ // Check if recursions fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion3,
+ compileOptions, kHasRecursion));
+ // Check ternary recursions fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion4,
+ compileOptions, kHasRecursion));
+ // Check ternary recursions fails.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion5,
+ compileOptions, kHasRecursion));
+ // Check unused recursions passes.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion6,
+ compileOptions, NULL));
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion7,
+ compileOptions, kHasRecursion));
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion8,
+ compileOptions, kHasRecursion));
+ // Check unused recursions fails if limiting call stack
+ // since we check all paths.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithRecursion6,
+ compileOptions | SH_LIMIT_CALL_STACK_DEPTH, kHasRecursion));
+
+ // Check unused recursions passes.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithNoRecursion,
+ compileOptions, NULL));
+ // Check unused recursions passes if limiting call stack.
+ EXPECT_TRUE(CheckShaderCompilation(
+ vertexCompiler, shaderWithNoRecursion,
+ compileOptions | SH_LIMIT_CALL_STACK_DEPTH, NULL));
+}
+
diff --git a/tests/compiler_tests/VariablePacker_test.cpp b/tests/compiler_tests/VariablePacker_test.cpp
new file mode 100644
index 00000000..6405ea70
--- /dev/null
+++ b/tests/compiler_tests/VariablePacker_test.cpp
@@ -0,0 +1,85 @@
+//
+// 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.
+//
+#include "compiler/VariablePacker.h"
+#include "gtest/gtest.h"
+
+TEST(VariablePacking, Pack) {
+ VariablePacker packer;
+ TVariableInfoList vars;
+ const int kMaxRows = 16;
+ // test no vars.
+ EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+ ShDataType types[] = {
+ SH_FLOAT_MAT4, // 0
+ SH_FLOAT_MAT2, // 1
+ SH_FLOAT_VEC4, // 2
+ SH_INT_VEC4, // 3
+ SH_BOOL_VEC4, // 4
+ SH_FLOAT_MAT3, // 5
+ SH_FLOAT_VEC3, // 6
+ SH_INT_VEC3, // 7
+ SH_BOOL_VEC3, // 8
+ SH_FLOAT_VEC2, // 9
+ SH_INT_VEC2, // 10
+ SH_BOOL_VEC2, // 11
+ SH_FLOAT, // 12
+ SH_INT, // 13
+ SH_BOOL, // 14
+ SH_SAMPLER_2D, // 15
+ SH_SAMPLER_CUBE, // 16
+ SH_SAMPLER_EXTERNAL_OES, // 17
+ SH_SAMPLER_2D_RECT_ARB, // 18
+ };
+
+ for (size_t tt = 0; tt < sizeof(types) / sizeof(types[0]); ++tt) {
+ ShDataType type = types[tt];
+ int num_rows = VariablePacker::GetNumRows(type);
+ int num_components_per_row = VariablePacker::GetNumComponentsPerRow(type);
+ // Check 1 of the type.
+ vars.clear();
+ vars.push_back(TVariableInfo(type, 1));
+ EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+ // Check exactly the right amount of 1 type as an array.
+ int num_vars = kMaxRows / num_rows;
+ vars.clear();
+ vars.push_back(TVariableInfo(type, num_vars));
+ EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+ // test too many
+ vars.clear();
+ vars.push_back(TVariableInfo(type, num_vars + 1));
+ EXPECT_FALSE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+ // Check exactly the right amount of 1 type as individual vars.
+ num_vars = kMaxRows / num_rows *
+ ((num_components_per_row > 2) ? 1 : (4 / num_components_per_row));
+ vars.clear();
+ for (int ii = 0; ii < num_vars; ++ii) {
+ vars.push_back(TVariableInfo(type, 1));
+ }
+ EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+
+ // Check 1 too many.
+ vars.push_back(TVariableInfo( type, 1));
+ EXPECT_FALSE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+ }
+
+ // Test example from GLSL ES 3.0 spec chapter 11.
+ vars.clear();
+ vars.push_back(TVariableInfo(SH_FLOAT_VEC4, 1));
+ vars.push_back(TVariableInfo(SH_FLOAT_MAT3, 1));
+ vars.push_back(TVariableInfo(SH_FLOAT_MAT3, 1));
+ vars.push_back(TVariableInfo(SH_FLOAT_VEC2, 6));
+ vars.push_back(TVariableInfo(SH_FLOAT_VEC2, 4));
+ vars.push_back(TVariableInfo(SH_FLOAT_VEC2, 1));
+ vars.push_back(TVariableInfo(SH_FLOAT, 3));
+ vars.push_back(TVariableInfo(SH_FLOAT, 2));
+ vars.push_back(TVariableInfo(SH_FLOAT, 1));
+ EXPECT_TRUE(packer.CheckVariablesWithinPackingLimits(kMaxRows, vars));
+}
+
diff --git a/tests/preprocessor_tests/MockDiagnostics.h b/tests/preprocessor_tests/MockDiagnostics.h
new file mode 100644
index 00000000..1fcedb48
--- /dev/null
+++ b/tests/preprocessor_tests/MockDiagnostics.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef PREPROCESSOR_TESTS_MOCK_DIAGNOSTICS_H_
+#define PREPROCESSOR_TESTS_MOCK_DIAGNOSTICS_H_
+
+#include "gmock/gmock.h"
+#include "DiagnosticsBase.h"
+
+class MockDiagnostics : public pp::Diagnostics
+{
+ public:
+ MOCK_METHOD3(print,
+ void(ID id, const pp::SourceLocation& loc, const std::string& text));
+};
+
+#endif // PREPROCESSOR_TESTS_MOCK_DIAGNOSTICS_H_
diff --git a/tests/preprocessor_tests/MockDirectiveHandler.h b/tests/preprocessor_tests/MockDirectiveHandler.h
new file mode 100644
index 00000000..f2893fd9
--- /dev/null
+++ b/tests/preprocessor_tests/MockDirectiveHandler.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef PREPROCESSOR_TESTS_MOCK_DIRECTIVE_HANDLER_H_
+#define PREPROCESSOR_TESTS_MOCK_DIRECTIVE_HANDLER_H_
+
+#include "gmock/gmock.h"
+#include "DirectiveHandlerBase.h"
+
+class MockDirectiveHandler : public pp::DirectiveHandler
+{
+ public:
+ MOCK_METHOD2(handleError,
+ void(const pp::SourceLocation& loc, const std::string& msg));
+
+ MOCK_METHOD3(handlePragma,
+ void(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& value));
+
+ MOCK_METHOD3(handleExtension,
+ void(const pp::SourceLocation& loc,
+ const std::string& name,
+ const std::string& behavior));
+
+ MOCK_METHOD2(handleVersion,
+ void(const pp::SourceLocation& loc, int version));
+};
+
+#endif // PREPROCESSOR_TESTS_MOCK_DIRECTIVE_HANDLER_H_
diff --git a/tests/preprocessor_tests/PreprocessorTest.cpp b/tests/preprocessor_tests/PreprocessorTest.cpp
new file mode 100644
index 00000000..9f90484f
--- /dev/null
+++ b/tests/preprocessor_tests/PreprocessorTest.cpp
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+void PreprocessorTest::preprocess(const char* input, const char* expected)
+{
+ ASSERT_TRUE(mPreprocessor.init(1, &input, NULL));
+
+ int line = 1;
+ pp::Token token;
+ std::stringstream stream;
+ do
+ {
+ mPreprocessor.lex(&token);
+ for (; line < token.location.line; ++line)
+ {
+ stream << "\n";
+ }
+ stream << token;
+ } while (token.type != pp::Token::LAST);
+
+ std::string actual = stream.str();
+ EXPECT_STREQ(expected, actual.c_str());
+}
diff --git a/tests/preprocessor_tests/PreprocessorTest.h b/tests/preprocessor_tests/PreprocessorTest.h
new file mode 100644
index 00000000..e8184de0
--- /dev/null
+++ b/tests/preprocessor_tests/PreprocessorTest.h
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "gtest/gtest.h"
+
+#include "MockDiagnostics.h"
+#include "MockDirectiveHandler.h"
+#include "Preprocessor.h"
+
+#ifndef PREPROCESSOR_TESTS_PREPROCESSOR_TEST_H_
+#define PREPROCESSOR_TESTS_PREPROCESSOR_TEST_H_
+
+class PreprocessorTest : public testing::Test
+{
+ protected:
+ PreprocessorTest() : mPreprocessor(&mDiagnostics, &mDirectiveHandler) { }
+
+ // Preprocesses the input string and verifies that it matches
+ // expected output.
+ void preprocess(const char* input, const char* expected);
+
+ MockDiagnostics mDiagnostics;
+ MockDirectiveHandler mDirectiveHandler;
+ pp::Preprocessor mPreprocessor;
+};
+
+#endif // PREPROCESSOR_TESTS_PREPROCESSOR_TEST_H_
diff --git a/tests/preprocessor_tests/char_test.cpp b/tests/preprocessor_tests/char_test.cpp
new file mode 100644
index 00000000..e6576a0b
--- /dev/null
+++ b/tests/preprocessor_tests/char_test.cpp
@@ -0,0 +1,98 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include <algorithm>
+#include <climits>
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class CharTest : public PreprocessorTest,
+ public testing::WithParamInterface<int>
+{
+};
+
+static const char kPunctuators[] = {
+ '.', '+', '-', '/', '*', '%', '<', '>', '[', ']', '(', ')', '{', '}',
+ '^', '|', '&', '~', '=', '!', ':', ';', ',', '?'};
+static const int kNumPunctuators =
+ sizeof(kPunctuators) / sizeof(kPunctuators[0]);
+
+bool isPunctuator(char c)
+{
+ static const char* kPunctuatorBeg = kPunctuators;
+ static const char* kPunctuatorEnd = kPunctuators + kNumPunctuators;
+ return std::find(kPunctuatorBeg, kPunctuatorEnd, c) != kPunctuatorEnd;
+}
+
+static const char kWhitespaces[] = {' ', '\t', '\v', '\f', '\n', '\r'};
+static const int kNumWhitespaces =
+ sizeof(kWhitespaces) / sizeof(kWhitespaces[0]);
+
+bool isWhitespace(char c)
+{
+ static const char* kWhitespaceBeg = kWhitespaces;
+ static const char* kWhitespaceEnd = kWhitespaces + kNumWhitespaces;
+ return std::find(kWhitespaceBeg, kWhitespaceEnd, c) != kWhitespaceEnd;
+}
+
+TEST_P(CharTest, Identified)
+{
+ std::string str(1, GetParam());
+ const char* cstr = str.c_str();
+ int length = 1;
+
+ // Note that we pass the length param as well because the invalid
+ // string may contain the null character.
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, &length));
+
+ int expectedType = pp::Token::LAST;
+ std::string expectedValue;
+
+ if (str[0] == '#')
+ {
+ // Lone '#' is ignored.
+ }
+ else if ((str[0] == '_') ||
+ ((str[0] >= 'a') && (str[0] <= 'z')) ||
+ ((str[0] >= 'A') && (str[0] <= 'Z')))
+ {
+ expectedType = pp::Token::IDENTIFIER;
+ expectedValue = str;
+ }
+ else if (str[0] >= '0' && str[0] <= '9')
+ {
+ expectedType = pp::Token::CONST_INT;
+ expectedValue = str;
+ }
+ else if (isPunctuator(str[0]))
+ {
+ expectedType = str[0];
+ expectedValue = str;
+ }
+ else if (isWhitespace(str[0]))
+ {
+ // Whitespace is ignored.
+ }
+ else
+ {
+ // Everything else is invalid.
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::INVALID_CHARACTER, _, str));
+ }
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(expectedType, token.type);
+ EXPECT_EQ(expectedValue, token.text);
+};
+
+// Note +1 for the max-value in range. It is there because the max-value
+// not included in the range.
+INSTANTIATE_TEST_CASE_P(All, CharTest,
+ testing::Range(CHAR_MIN, CHAR_MAX + 1));
+
diff --git a/tests/preprocessor_tests/comment_test.cpp b/tests/preprocessor_tests/comment_test.cpp
new file mode 100644
index 00000000..27f78cf1
--- /dev/null
+++ b/tests/preprocessor_tests/comment_test.cpp
@@ -0,0 +1,69 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class CommentTest : public PreprocessorTest,
+ public testing::WithParamInterface<const char*>
+{
+};
+
+TEST_P(CommentTest, CommentIgnored)
+{
+ const char* str = GetParam();
+
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+}
+
+INSTANTIATE_TEST_CASE_P(LineComment, CommentTest,
+ testing::Values("//foo\n", // With newline.
+ "//foo", // Without newline.
+ "//**/", // Nested block comment.
+ "////", // Nested line comment.
+ "//\"")); // Invalid character.
+
+INSTANTIATE_TEST_CASE_P(BlockComment, CommentTest,
+ testing::Values("/*foo*/",
+ "/*foo\n*/", // With newline.
+ "/*//*/", // Nested line comment.
+ "/*/**/", // Nested block comment.
+ "/***/", // With lone '*'.
+ "/*\"*/")); // Invalid character.
+
+class BlockCommentTest : public PreprocessorTest
+{
+};
+
+TEST_F(BlockCommentTest, CommentReplacedWithSpace)
+{
+ const char* str = "/*foo*/bar";
+
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("bar", token.text);
+ EXPECT_TRUE(token.hasLeadingSpace());
+}
+
+TEST_F(BlockCommentTest, UnterminatedComment)
+{
+ const char* str = "/*foo";
+
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::EOF_IN_COMMENT, _, _));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
diff --git a/tests/preprocessor_tests/define_test.cpp b/tests/preprocessor_tests/define_test.cpp
new file mode 100644
index 00000000..bb72016b
--- /dev/null
+++ b/tests/preprocessor_tests/define_test.cpp
@@ -0,0 +1,893 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class DefineTest : public PreprocessorTest
+{
+};
+
+TEST_F(DefineTest, NonIdentifier)
+{
+ const char* input = "#define 2 foo\n"
+ "2\n";
+ const char* expected = "\n"
+ "2\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 1),
+ "2"));
+
+ preprocess(input, expected);
+};
+
+TEST_F(DefineTest, RedefinePredefined)
+{
+ const char* input = "#define __LINE__ 10\n"
+ "__LINE__\n"
+ "#define __FILE__ 20\n"
+ "__FILE__\n"
+ "#define __VERSION__ 200\n"
+ "__VERSION__\n"
+ "#define GL_ES 0\n"
+ "GL_ES\n";
+ const char* expected = "\n"
+ "2\n"
+ "\n"
+ "0\n"
+ "\n"
+ "100\n"
+ "\n"
+ "1\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_PREDEFINED_REDEFINED,
+ pp::SourceLocation(0, 1),
+ "__LINE__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_PREDEFINED_REDEFINED,
+ pp::SourceLocation(0, 3),
+ "__FILE__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_PREDEFINED_REDEFINED,
+ pp::SourceLocation(0, 5),
+ "__VERSION__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_PREDEFINED_REDEFINED,
+ pp::SourceLocation(0, 7),
+ "GL_ES"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ReservedUnderScore1)
+{
+ const char* input = "#define __foo bar\n"
+ "__foo\n";
+ const char* expected = "\n"
+ "__foo\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_NAME_RESERVED,
+ pp::SourceLocation(0, 1),
+ "__foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ReservedUnderScore2)
+{
+ const char* input = "#define foo__bar baz\n"
+ "foo__bar\n";
+ const char* expected = "\n"
+ "foo__bar\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_NAME_RESERVED,
+ pp::SourceLocation(0, 1),
+ "foo__bar"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ReservedGL)
+{
+ const char* input = "#define GL_foo bar\n"
+ "GL_foo\n";
+ const char* expected = "\n"
+ "GL_foo\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_NAME_RESERVED,
+ pp::SourceLocation(0, 1),
+ "GL_foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjRedefineValid)
+{
+ const char* input = "#define foo (1-1)\n"
+ "#define foo /* whitespace */ (1-1) /* other */ \n"
+ "foo\n";
+ const char* expected = "\n"
+ "\n"
+ "(1-1)\n";
+ // No error or warning.
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjRedefineInvalid)
+{
+ const char* input = "#define foo (0)\n"
+ "#define foo (1-1)\n"
+ "foo\n";
+ const char* expected = "\n"
+ "\n"
+ "(0)\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_REDEFINED,
+ pp::SourceLocation(0, 2),
+ "foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncRedefineValid)
+{
+ const char* input = "#define foo(a) ( a )\n"
+ "#define foo( a )( /* whitespace */ a /* other */ )\n"
+ "foo(b)\n";
+ const char* expected = "\n"
+ "\n"
+ "( b )\n";
+ // No error or warning.
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncRedefineInvalid)
+{
+ const char* input = "#define foo(b) ( a )\n"
+ "#define foo(b) ( b )\n"
+ "foo(1)\n";
+ const char* expected = "\n"
+ "\n"
+ "( a )\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_REDEFINED,
+ pp::SourceLocation(0, 2),
+ "foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjBasic)
+{
+ const char* input = "#define foo 1\n"
+ "foo\n";
+ const char* expected = "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjEmpty)
+{
+ const char* input = "#define foo\n"
+ "foo\n";
+ const char* expected = "\n"
+ "\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjChain)
+{
+ const char* input = "#define foo 1\n"
+ "#define bar foo\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjChainReverse)
+{
+ const char* input = "#define bar foo\n"
+ "#define foo 1\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjRecursive)
+{
+ const char* input = "#define foo bar\n"
+ "#define bar baz\n"
+ "#define baz foo\n"
+ "foo\n"
+ "bar\n"
+ "baz\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "foo\n"
+ "bar\n"
+ "baz\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjCompositeChain)
+{
+ const char* input = "#define foo 1\n"
+ "#define bar a foo\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "a 1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjCompositeChainReverse)
+{
+ const char* input = "#define bar a foo\n"
+ "#define foo 1\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "a 1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjCompositeRecursive)
+{
+ const char* input = "#define foo a bar\n"
+ "#define bar b baz\n"
+ "#define baz c foo\n"
+ "foo\n"
+ "bar\n"
+ "baz\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "a b c foo\n"
+ "b c a bar\n"
+ "c a b baz\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjChainSelfRecursive)
+{
+ const char* input = "#define foo foo\n"
+ "#define bar foo\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "foo\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjectLikeWithParens)
+{
+ const char* input = "#define foo ()1\n"
+ "foo()\n"
+ "#define bar ()2\n"
+ "bar()\n";
+ const char* expected = "\n"
+ "()1()\n"
+ "\n"
+ "()2()\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncEmpty)
+{
+ const char* input = "#define foo()\n"
+ "foo()\n";
+ const char* expected = "\n"
+ "\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncNoArgs)
+{
+ const char* input = "#define foo() bar\n"
+ "foo()\n";
+ const char* expected = "\n"
+ "bar\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncOneArgUnused)
+{
+ const char* input = "#define foo(x) 1\n"
+ "foo(bar)\n";
+ const char* expected = "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncTwoArgsUnused)
+{
+ const char* input = "#define foo(x,y) 1\n"
+ "foo(bar,baz)\n";
+ const char* expected = "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncOneArg)
+{
+ const char* input = "#define foo(x) ((x)+1)\n"
+ "foo(bar)\n";
+ const char* expected = "\n"
+ "((bar)+1)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncTwoArgs)
+{
+ const char* input = "#define foo(x,y) ((x)*(y))\n"
+ "foo(bar,baz)\n";
+ const char* expected = "\n"
+ "((bar)*(baz))\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncEmptyArgs)
+{
+ const char* input = "#define zero() pass\n"
+ "#define one(x) pass\n"
+ "#define two(x,y) pass\n"
+ "zero()\n"
+ "one()\n"
+ "two(,)\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass\n"
+ "pass\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncMacroAsParam)
+{
+ const char* input = "#define x 0\n"
+ "#define foo(x) x\n"
+ "foo(1)\n";
+ const char* expected = "\n"
+ "\n"
+ "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncOneArgMulti)
+{
+ const char* input = "#define foo(x) (x)\n"
+ "foo(this is a multi-word argument)\n";
+ const char* expected = "\n"
+ "(this is a multi-word argument)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncTwoArgsMulti)
+{
+ const char* input = "#define foo(x,y) x,two fish,red fish,y\n"
+ "foo(one fish, blue fish)\n";
+ const char* expected = "\n"
+ "one fish,two fish,red fish,blue fish\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncCompose)
+{
+ const char* input = "#define bar(x) (1+(x))\n"
+ "#define foo(y) (2*(y))\n"
+ "foo(bar(3))\n";
+ const char* expected = "\n"
+ "\n"
+ "(2*((1+(3))))\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncArgWithParens)
+{
+ const char* input = "#define foo(x) (x)\n"
+ "foo(argument(with parens) FTW)\n";
+ const char* expected = "\n"
+ "(argument(with parens) FTW)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncMacroAsNonMacro)
+{
+ const char* input = "#define foo(bar) bar\n"
+ "foo bar\n";
+ const char* expected = "\n"
+ "foo bar\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncExtraNewlines)
+{
+ const char* input = "#define foo(a) (a)\n"
+ "foo\n"
+ "(\n"
+ "1\n"
+ ")\n";
+ const char* expected = "\n"
+ "(1)\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFunc)
+{
+ const char* input = "#define foo() pass\n"
+ "#define bar foo()\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToNonFunc)
+{
+ const char* input = "#define pass() fail\n"
+ "#define bar pass\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncWithArgs)
+{
+ const char* input = "#define foo(fail) fail\n"
+ "#define bar foo(pass)\n"
+ "bar\n";
+ const char* expected = "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncCompose)
+{
+ const char* input = "#define baz(fail) fail\n"
+ "#define bar(fail) fail\n"
+ "#define foo bar(baz(pass))\n"
+ "foo\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncParensInText1)
+{
+ const char* input = "#define fail() pass\n"
+ "#define foo fail\n"
+ "foo()\n";
+ const char* expected = "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncParensInText2)
+{
+ const char* input = "#define bar with,embedded,commas\n"
+ "#define func(x) pass\n"
+ "#define foo func\n"
+ "foo(bar)\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainObjToFuncMultiLevel)
+{
+ const char* input = "#define foo(x) pass\n"
+ "#define bar foo\n"
+ "#define baz bar\n"
+ "#define joe baz\n"
+ "joe (fail)\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ObjToFuncRecursive)
+{
+ const char* input = "#define A(a,b) B(a,b)\n"
+ "#define C A(0,C)\n"
+ "C\n";
+ const char* expected = "\n"
+ "\n"
+ "B(0,C)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, ChainFuncToFuncCompose)
+{
+ const char* input = "#define baz(fail) fail\n"
+ "#define bar(fail) fail\n"
+ "#define foo() bar(baz(pass))\n"
+ "foo()\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncSelfRecursive)
+{
+ const char* input = "#define foo(a) foo(2*(a))\n"
+ "foo(3)\n";
+ const char* expected = "\n"
+ "foo(2*(3))\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncSelfCompose)
+{
+ const char* input = "#define foo(a) foo(2*(a))\n"
+ "foo(foo(3))\n";
+ const char* expected = "\n"
+ "foo(2*(foo(2*(3))))\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncSelfComposeNonFunc)
+{
+ const char* input = "#define foo(bar) bar\n"
+ "foo(foo)\n";
+ const char* expected = "\n"
+ "foo\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncSelfComposeNonFuncMultiTokenArg)
+{
+ const char* input = "#define foo(bar) bar\n"
+ "foo(1+foo)\n";
+ const char* expected = "\n"
+ "1+foo\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FinalizeUnexpandedMacro)
+{
+ const char* input = "#define expand(x) expand(x once)\n"
+ "#define foo(x) x\n"
+ "foo(expand(just))\n";
+ const char* expected = "\n"
+ "\n"
+ "expand(just once)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncArgWithCommas)
+{
+ const char* input = "#define foo(x) pass\n"
+ "foo(argument (with,embedded, commas) -- baz)\n";
+ const char* expected = "\n"
+ "pass\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncArgObjMaroWithComma)
+{
+ const char* input = "#define foo(a) (a)\n"
+ "#define bar two,words\n"
+ "foo(bar)\n";
+ const char* expected = "\n"
+ "\n"
+ "(two,words)\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncLeftParenInMacroRightParenInText)
+{
+ const char* input = "#define bar(a) a*2\n"
+ "#define foo bar(\n"
+ "foo b)\n";
+ const char* expected = "\n"
+ "\n"
+ "b*2\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, RepeatedArg)
+{
+ const char* input = "#define double(x) x x\n"
+ "double(1)\n";
+ const char* expected = "\n"
+ "1 1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncMissingRightParen)
+{
+ const char* input = "#define foo(x) (2*(x))\n"
+ "foo(3\n";
+ const char* expected = "\n"
+ "\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_UNTERMINATED_INVOCATION,
+ pp::SourceLocation(0, 2),
+ "foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, FuncIncorrectArgCount)
+{
+ const char* input = "#define foo(x,y) ((x)+(y))\n"
+ "foo()\n"
+ "foo(1)\n"
+ "foo(1,2,3)\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_TOO_FEW_ARGS,
+ pp::SourceLocation(0, 2),
+ "foo"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_TOO_FEW_ARGS,
+ pp::SourceLocation(0, 3),
+ "foo"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_TOO_MANY_ARGS,
+ pp::SourceLocation(0, 4),
+ "foo"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, Undef)
+{
+ const char* input = "#define foo 1\n"
+ "foo\n"
+ "#undef foo\n"
+ "foo\n";
+ const char* expected = "\n"
+ "1\n"
+ "\n"
+ "foo\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, UndefPredefined)
+{
+ const char* input = "#undef __LINE__\n"
+ "__LINE__\n"
+ "#undef __FILE__\n"
+ "__FILE__\n"
+ "#undef __VERSION__\n"
+ "__VERSION__\n"
+ "#undef GL_ES\n"
+ "GL_ES\n";
+ const char* expected = "\n"
+ "2\n"
+ "\n"
+ "0\n"
+ "\n"
+ "100\n"
+ "\n"
+ "1\n";
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+ pp::SourceLocation(0, 1),
+ "__LINE__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+ pp::SourceLocation(0, 3),
+ "__FILE__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+ pp::SourceLocation(0, 5),
+ "__VERSION__"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+ pp::SourceLocation(0, 7),
+ "GL_ES"));
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, UndefRedefine)
+{
+ const char* input = "#define foo 1\n"
+ "foo\n"
+ "#undef foo\n"
+ "foo\n"
+ "#define foo 2\n"
+ "foo\n";
+ const char* expected = "\n"
+ "1\n"
+ "\n"
+ "foo\n"
+ "\n"
+ "2\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, C99Example)
+{
+ const char* input =
+ "#define x 3 \n"
+ "#define f(a) f(x * (a)) \n"
+ "#undef x \n"
+ "#define x 2 \n"
+ "#define g f \n"
+ "#define z z[0] \n"
+ "#define h g(~ \n"
+ "#define m(a) a(w) \n"
+ "#define w 0,1 \n"
+ "#define t(a) a \n"
+ "#define p() int \n"
+ "#define q(x) x \n"
+ " \n"
+ "f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);\n"
+ "g(x+(3,4)-w) | h 5) & m\n"
+ " (f)^m(m);\n"
+ "p() i[q()] = { q(1), 23, 4, 5, };\n";
+ const char* expected =
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);\n"
+ "f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))\n"
+ "^m(0,1);\n"
+ "int i[] = { 1, 23, 4, 5, };\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, Predefined_GL_ES)
+{
+ const char* input = "GL_ES\n";
+ const char* expected = "1\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, Predefined_VERSION)
+{
+ const char* input = "__VERSION__\n";
+ const char* expected = "100\n";
+
+ preprocess(input, expected);
+}
+
+TEST_F(DefineTest, Predefined_LINE1)
+{
+ const char* str = "\n\n__LINE__";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ("3", token.text);
+}
+
+TEST_F(DefineTest, Predefined_LINE2)
+{
+ const char* str = "#line 10\n"
+ "__LINE__\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ("10", token.text);
+}
+
+TEST_F(DefineTest, Predefined_FILE1)
+{
+ const char* const str[] = {"", "", "__FILE__"};
+ ASSERT_TRUE(mPreprocessor.init(3, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ("2", token.text);
+}
+
+TEST_F(DefineTest, Predefined_FILE2)
+{
+ const char* const str[] = {"#line 10 20\n", "__FILE__"};
+ ASSERT_TRUE(mPreprocessor.init(2, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ("21", token.text);
+}
diff --git a/tests/preprocessor_tests/error_test.cpp b/tests/preprocessor_tests/error_test.cpp
new file mode 100644
index 00000000..c9e0c40f
--- /dev/null
+++ b/tests/preprocessor_tests/error_test.cpp
@@ -0,0 +1,92 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class ErrorTest : public PreprocessorTest
+{
+};
+
+TEST_F(ErrorTest, Empty)
+{
+ const char* str = "#error\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler, handleError(pp::SourceLocation(0, 1), ""));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ErrorTest, OneTokenMessage)
+{
+ const char* str = "#error foo\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleError(pp::SourceLocation(0, 1), " foo"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ErrorTest, TwoTokenMessage)
+{
+ const char* str = "#error foo bar\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleError(pp::SourceLocation(0, 1), " foo bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ErrorTest, Comments)
+{
+ const char* str = "/*foo*/"
+ "#"
+ "/*foo*/"
+ "error"
+ "/*foo*/"
+ "foo"
+ "/*foo*/"
+ "bar"
+ "/*foo*/"
+ "//foo"
+ "\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleError(pp::SourceLocation(0, 1), " foo bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ErrorTest, MissingNewline)
+{
+ const char* str = "#error foo";
+ const char* expected = "";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleError(pp::SourceLocation(0, 1), " foo"));
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::EOF_IN_DIRECTIVE, _, _));
+
+ preprocess(str, expected);
+}
diff --git a/tests/preprocessor_tests/extension_test.cpp b/tests/preprocessor_tests/extension_test.cpp
new file mode 100644
index 00000000..94b7eb70
--- /dev/null
+++ b/tests/preprocessor_tests/extension_test.cpp
@@ -0,0 +1,103 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class ExtensionTest : public PreprocessorTest
+{
+};
+
+TEST_F(ExtensionTest, Valid)
+{
+ const char* str = "#extension foo : bar\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleExtension(pp::SourceLocation(0, 1), "foo", "bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ExtensionTest, Comments)
+{
+ const char* str = "/*foo*/"
+ "#"
+ "/*foo*/"
+ "extension"
+ "/*foo*/"
+ "foo"
+ "/*foo*/"
+ ":"
+ "/*foo*/"
+ "bar"
+ "/*foo*/"
+ "//foo"
+ "\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleExtension(pp::SourceLocation(0, 1), "foo", "bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(ExtensionTest, MissingNewline)
+{
+ const char* str = "#extension foo : bar";
+ const char* expected = "";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleExtension(pp::SourceLocation(0, 1), "foo", "bar"));
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::EOF_IN_DIRECTIVE, _, _));
+
+ preprocess(str, expected);
+}
+
+struct ExtensionTestParam
+{
+ const char* str;
+ pp::Diagnostics::ID id;
+};
+
+using testing::WithParamInterface;
+class InvalidExtensionTest : public ExtensionTest,
+ public WithParamInterface<ExtensionTestParam>
+{
+};
+
+TEST_P(InvalidExtensionTest, Identified)
+{
+ ExtensionTestParam param = GetParam();
+ const char* expected = "\n";
+
+ using testing::_;
+ // No handleExtension call.
+ EXPECT_CALL(mDirectiveHandler, handleExtension(_, _, _)).Times(0);
+ // Invalid extension directive call.
+ EXPECT_CALL(mDiagnostics, print(param.id, pp::SourceLocation(0, 1), _));
+
+ preprocess(param.str, expected);
+}
+
+static const ExtensionTestParam kParams[] = {
+ {"#extension\n", pp::Diagnostics::INVALID_EXTENSION_DIRECTIVE},
+ {"#extension 1\n", pp::Diagnostics::INVALID_EXTENSION_NAME},
+ {"#extension foo bar\n", pp::Diagnostics::UNEXPECTED_TOKEN},
+ {"#extension foo : \n", pp::Diagnostics::INVALID_EXTENSION_DIRECTIVE},
+ {"#extension foo : 1\n", pp::Diagnostics::INVALID_EXTENSION_BEHAVIOR},
+ {"#extension foo : bar baz\n", pp::Diagnostics::UNEXPECTED_TOKEN}
+};
+INSTANTIATE_TEST_CASE_P(All, InvalidExtensionTest, testing::ValuesIn(kParams));
diff --git a/tests/preprocessor_tests/identifier_test.cpp b/tests/preprocessor_tests/identifier_test.cpp
new file mode 100644
index 00000000..f2653b8c
--- /dev/null
+++ b/tests/preprocessor_tests/identifier_test.cpp
@@ -0,0 +1,162 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+#define CLOSED_RANGE(x, y) testing::Range(x, static_cast<char>((y) + 1))
+
+class IdentifierTest : public PreprocessorTest
+{
+protected:
+ void expectIdentifier(const std::string& str)
+ {
+ const char* cstr = str.c_str();
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ(str, token.text);
+ }
+};
+
+class SingleLetterIdentifierTest : public IdentifierTest,
+ public testing::WithParamInterface<char>
+{
+};
+
+// This test covers identifier names of form [_a-zA-Z].
+TEST_P(SingleLetterIdentifierTest, Identified)
+{
+ std::string str(1, GetParam());
+ expectIdentifier(str);
+}
+
+// Test string: '_'
+INSTANTIATE_TEST_CASE_P(Underscore,
+ SingleLetterIdentifierTest,
+ testing::Values('_'));
+
+// Test string: [a-z]
+INSTANTIATE_TEST_CASE_P(a_z,
+ SingleLetterIdentifierTest,
+ CLOSED_RANGE('a', 'z'));
+
+// Test string: [A-Z]
+INSTANTIATE_TEST_CASE_P(A_Z,
+ SingleLetterIdentifierTest,
+ CLOSED_RANGE('A', 'Z'));
+
+typedef std::tr1::tuple<char, char> IdentifierParams;
+class DoubleLetterIdentifierTest :
+ public IdentifierTest,
+ public testing::WithParamInterface<IdentifierParams>
+{
+};
+
+// This test covers identifier names of form [_a-zA-Z][_a-zA-Z0-9].
+TEST_P(DoubleLetterIdentifierTest, Identified)
+{
+ std::string str;
+ str.push_back(std::tr1::get<0>(GetParam()));
+ str.push_back(std::tr1::get<1>(GetParam()));
+
+ expectIdentifier(str);
+}
+
+// Test string: "__"
+INSTANTIATE_TEST_CASE_P(Underscore_Underscore,
+ DoubleLetterIdentifierTest,
+ testing::Combine(testing::Values('_'),
+ testing::Values('_')));
+
+// Test string: "_"[a-z]
+INSTANTIATE_TEST_CASE_P(Underscore_a_z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(testing::Values('_'),
+ CLOSED_RANGE('a', 'z')));
+
+// Test string: "_"[A-Z]
+INSTANTIATE_TEST_CASE_P(Underscore_A_Z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(testing::Values('_'),
+ CLOSED_RANGE('A', 'Z')));
+
+// Test string: "_"[0-9]
+INSTANTIATE_TEST_CASE_P(Underscore_0_9,
+ DoubleLetterIdentifierTest,
+ testing::Combine(testing::Values('_'),
+ CLOSED_RANGE('0', '9')));
+
+// Test string: [a-z]"_"
+INSTANTIATE_TEST_CASE_P(a_z_Underscore,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('a', 'z'),
+ testing::Values('_')));
+
+// Test string: [a-z][a-z]
+INSTANTIATE_TEST_CASE_P(a_z_a_z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('a', 'z'),
+ CLOSED_RANGE('a', 'z')));
+
+// Test string: [a-z][A-Z]
+INSTANTIATE_TEST_CASE_P(a_z_A_Z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('a', 'z'),
+ CLOSED_RANGE('A', 'Z')));
+
+// Test string: [a-z][0-9]
+INSTANTIATE_TEST_CASE_P(a_z_0_9,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('a', 'z'),
+ CLOSED_RANGE('0', '9')));
+
+// Test string: [A-Z]"_"
+INSTANTIATE_TEST_CASE_P(A_Z_Underscore,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('A', 'Z'),
+ testing::Values('_')));
+
+// Test string: [A-Z][a-z]
+INSTANTIATE_TEST_CASE_P(A_Z_a_z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('A', 'Z'),
+ CLOSED_RANGE('a', 'z')));
+
+// Test string: [A-Z][A-Z]
+INSTANTIATE_TEST_CASE_P(A_Z_A_Z,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('A', 'Z'),
+ CLOSED_RANGE('A', 'Z')));
+
+// Test string: [A-Z][0-9]
+INSTANTIATE_TEST_CASE_P(A_Z_0_9,
+ DoubleLetterIdentifierTest,
+ testing::Combine(CLOSED_RANGE('A', 'Z'),
+ CLOSED_RANGE('0', '9')));
+
+// The tests above cover one-letter and various combinations of two-letter
+// identifier names. This test covers all characters in a single string.
+TEST_F(IdentifierTest, AllLetters)
+{
+ std::string str;
+ for (int c = 'a'; c <= 'z'; ++c)
+ str.push_back(c);
+
+ str.push_back('_');
+
+ for (int c = 'A'; c <= 'Z'; ++c)
+ str.push_back(c);
+
+ str.push_back('_');
+
+ for (int c = '0'; c <= '9'; ++c)
+ str.push_back(c);
+
+ expectIdentifier(str);
+}
diff --git a/tests/preprocessor_tests/if_test.cpp b/tests/preprocessor_tests/if_test.cpp
new file mode 100644
index 00000000..7a7548ff
--- /dev/null
+++ b/tests/preprocessor_tests/if_test.cpp
@@ -0,0 +1,835 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class IfTest : public PreprocessorTest
+{
+};
+
+TEST_F(IfTest, If_0)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail\n"
+ "#endif\n"
+ "pass_2\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_1)
+{
+ const char* str = "pass_1\n"
+ "#if 1\n"
+ "pass_2\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_0_Else)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail\n"
+ "#else\n"
+ "pass_2\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_1_Else)
+{
+ const char* str = "pass_1\n"
+ "#if 1\n"
+ "pass_2\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_0_Elif)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail_1\n"
+ "#elif 0\n"
+ "fail_2\n"
+ "#elif 1\n"
+ "pass_2\n"
+ "#elif 1\n"
+ "fail_3\n"
+ "#else\n"
+ "fail_4\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_1_Elif)
+{
+ const char* str = "pass_1\n"
+ "#if 1\n"
+ "pass_2\n"
+ "#elif 0\n"
+ "fail_1\n"
+ "#elif 1\n"
+ "fail_2\n"
+ "#else\n"
+ "fail_4\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_Elif_Else)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail_1\n"
+ "#elif 0\n"
+ "fail_2\n"
+ "#elif 0\n"
+ "fail_3\n"
+ "#else\n"
+ "pass_2\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_0_Nested)
+{
+ const char* str = "pass_1\n"
+ "#if 0\n"
+ "fail_1\n"
+ "#if 1\n"
+ "fail_2\n"
+ "#else\n"
+ "fail_3\n"
+ "#endif\n"
+ "#else\n"
+ "pass_2\n"
+ "#endif\n"
+ "pass_3\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, If_1_Nested)
+{
+ const char* str = "pass_1\n"
+ "#if 1\n"
+ "pass_2\n"
+ "#if 1\n"
+ "pass_3\n"
+ "#else\n"
+ "fail_1\n"
+ "#endif\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n"
+ "pass_4\n";
+ const char* expected = "pass_1\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "pass_3\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_4\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorPrecedence)
+{
+ const char* str = "#if 1 + 2 * 3 + - (26 % 17 - + 4 / 2)\n"
+ "fail_1\n"
+ "#else\n"
+ "pass_1\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass_1\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorDefined)
+{
+ const char* str = "#if defined foo\n"
+ "fail_1\n"
+ "#else\n"
+ "pass_1\n"
+ "#endif\n"
+ "#define foo\n"
+ "#if defined(foo)\n"
+ "pass_2\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n"
+ "#undef foo\n"
+ "#if defined ( foo ) \n"
+ "fail_3\n"
+ "#else\n"
+ "pass_3\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_3\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorEQ)
+{
+ const char* str = "#if 4 - 1 == 2 + 1\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorNE)
+{
+ const char* str = "#if 1 != 2\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorLess)
+{
+ const char* str = "#if 1 < 2\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorGreater)
+{
+ const char* str = "#if 2 > 1\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorLE)
+{
+ const char* str = "#if 1 <= 2\n"
+ "pass_1\n"
+ "#else\n"
+ "fail_1\n"
+ "#endif\n"
+ "#if 2 <= 2\n"
+ "pass_2\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorGE)
+{
+ const char* str = "#if 2 >= 1\n"
+ "pass_1\n"
+ "#else\n"
+ "fail_1\n"
+ "#endif\n"
+ "#if 2 >= 2\n"
+ "pass_2\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorBitwiseOR)
+{
+ const char* str = "#if (0xaaaaaaaa | 0x55555555) == 0xffffffff\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorBitwiseAND)
+{
+ const char* str = "#if (0xaaaaaaa & 0x5555555) == 0\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorBitwiseXOR)
+{
+ const char* str = "#if (0xaaaaaaa ^ 0x5555555) == 0xfffffff\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorBitwiseComplement)
+{
+ const char* str = "#if (~ 0xdeadbeef) == -3735928560\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorLeft)
+{
+ const char* str = "#if (1 << 12) == 4096\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, OperatorRight)
+{
+ const char* str = "#if (31762 >> 8) == 124\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, ExpressionWithMacros)
+{
+ const char* str = "#define one 1\n"
+ "#define two 2\n"
+ "#define three 3\n"
+ "#if one + two == three\n"
+ "pass\n"
+ "#else\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, JunkInsideExcludedBlockIgnored)
+{
+ const char* str = "#if 0\n"
+ "foo !@#$%^&* .1bar\n"
+ "#foo\n"
+ "#if bar\n"
+ "fail\n"
+ "#endif\n"
+ "#else\n"
+ "pass\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, Ifdef)
+{
+ const char* str = "#define foo\n"
+ "#ifdef foo\n"
+ "pass_1\n"
+ "#else\n"
+ "fail_1\n"
+ "#endif\n"
+ "#undef foo\n"
+ "#ifdef foo\n"
+ "fail_2\n"
+ "#else\n"
+ "pass_2\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, Ifndef)
+{
+ const char* str = "#define foo\n"
+ "#ifndef foo\n"
+ "fail_1\n"
+ "#else\n"
+ "pass_1\n"
+ "#endif\n"
+ "#undef foo\n"
+ "#ifndef foo\n"
+ "pass_2\n"
+ "#else\n"
+ "fail_2\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_1\n"
+ "\n"
+ "\n"
+ "\n"
+ "pass_2\n"
+ "\n"
+ "\n"
+ "\n";
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, MissingExpression)
+{
+ const char* str = "#if\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::INVALID_EXPRESSION,
+ pp::SourceLocation(0, 1),
+ "syntax error"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, DivisionByZero)
+{
+ const char* str = "#if 1 / (3 - (1 + 2))\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::DIVISION_BY_ZERO,
+ pp::SourceLocation(0, 1), "1 / 0"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, ModuloByZero)
+{
+ const char* str = "#if 1 % (3 - (1 + 2))\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::DIVISION_BY_ZERO,
+ pp::SourceLocation(0, 1), "1 % 0"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, DecIntegerOverflow)
+{
+ const char* str = "#if 4294967296\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::INTEGER_OVERFLOW,
+ pp::SourceLocation(0, 1), "4294967296"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, OctIntegerOverflow)
+{
+ const char* str = "#if 077777777777\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::INTEGER_OVERFLOW,
+ pp::SourceLocation(0, 1), "077777777777"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, HexIntegerOverflow)
+{
+ const char* str = "#if 0xfffffffff\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::INTEGER_OVERFLOW,
+ pp::SourceLocation(0, 1), "0xfffffffff"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, UndefinedMacro)
+{
+ const char* str = "#if UNDEFINED\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::INVALID_EXPRESSION,
+ pp::SourceLocation(0, 1),
+ "syntax error"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+ pp::SourceLocation(0, 1),
+ "UNDEFINED"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, InvalidExpressionIgnoredForExcludedElif)
+{
+ const char* str = "#if 1\n"
+ "pass\n"
+ "#elif UNDEFINED\n"
+ "fail\n"
+ "#endif\n";
+ const char* expected = "\n"
+ "pass\n"
+ "\n"
+ "\n"
+ "\n";
+
+ // No error or warning.
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(IfTest, ElseWithoutIf)
+{
+ const char* str = "#else\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
+ pp::SourceLocation(0, 1),
+ "else"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, ElifWithoutIf)
+{
+ const char* str = "#elif 1\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
+ pp::SourceLocation(0, 1),
+ "elif"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, EndifWithoutIf)
+{
+ const char* str = "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
+ pp::SourceLocation(0, 1),
+ "endif"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, ElseAfterElse)
+{
+ const char* str = "#if 1\n"
+ "#else\n"
+ "#else\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
+ pp::SourceLocation(0, 3),
+ "else"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, ElifAfterElse)
+{
+ const char* str = "#if 1\n"
+ "#else\n"
+ "#elif 0\n"
+ "#endif\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
+ pp::SourceLocation(0, 3),
+ "elif"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, UnterminatedIf)
+{
+ const char* str = "#if 1\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::CONDITIONAL_UNTERMINATED,
+ pp::SourceLocation(0, 1),
+ "if"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+TEST_F(IfTest, UnterminatedIfdef)
+{
+ const char* str = "#ifdef foo\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::CONDITIONAL_UNTERMINATED,
+ pp::SourceLocation(0, 1),
+ "ifdef"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
diff --git a/tests/preprocessor_tests/input_test.cpp b/tests/preprocessor_tests/input_test.cpp
new file mode 100644
index 00000000..b6a132af
--- /dev/null
+++ b/tests/preprocessor_tests/input_test.cpp
@@ -0,0 +1,161 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Input.h"
+#include "Token.h"
+
+class InitTest : public PreprocessorTest
+{
+};
+
+TEST_F(InitTest, NegativeCount)
+{
+ EXPECT_FALSE(mPreprocessor.init(-1, NULL, NULL));
+}
+
+TEST_F(InitTest, ZeroCount)
+{
+ EXPECT_TRUE(mPreprocessor.init(0, NULL, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+}
+
+TEST_F(InitTest, NullString)
+{
+ EXPECT_FALSE(mPreprocessor.init(1, NULL, NULL));
+}
+
+TEST(InputTest, DefaultConstructor)
+{
+ pp::Input input;
+ EXPECT_EQ(0, input.count());
+ EXPECT_EQ(0, input.read(NULL, 1));
+}
+
+TEST(InputTest, NullLength)
+{
+ const char* str[] = {"foo"};
+ pp::Input input(1, str, NULL);
+ EXPECT_EQ(3, input.length(0));
+}
+
+TEST(InputTest, NegativeLength)
+{
+ const char* str[] = {"foo"};
+ int length[] = {-1};
+ pp::Input input(1, str, length);
+ EXPECT_EQ(3, input.length(0));
+}
+
+TEST(InputTest, ActualLength)
+{
+ const char* str[] = {"foobar"};
+ int length[] = {3};
+ pp::Input input(1, str, length);
+ // Note that strlen(str[0]) != length[0].
+ // Even then Input should just accept any non-negative number.
+ EXPECT_EQ(length[0], input.length(0));
+}
+
+TEST(InputTest, String)
+{
+ const char* str[] = {"foo"};
+ pp::Input input(1, str, NULL);
+ EXPECT_STREQ(str[0], input.string(0));
+}
+
+TEST(InputTest, ReadSingleString)
+{
+ int count = 1;
+ const char* str[] = {"foo"};
+ char buf[4] = {'\0', '\0', '\0', '\0'};
+
+ int maxSize = 1;
+ pp::Input input1(count, str, NULL);
+ EXPECT_EQ(1, input1.read(buf, maxSize));
+ EXPECT_EQ('f', buf[0]);
+ EXPECT_EQ(1, input1.read(buf, maxSize));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(1, input1.read(buf, maxSize));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(0, input1.read(buf, maxSize));
+
+ maxSize = 2;
+ pp::Input input2(count, str, NULL);
+ EXPECT_EQ(2, input2.read(buf, maxSize));
+ EXPECT_STREQ("fo", buf);
+ EXPECT_EQ(1, input2.read(buf, maxSize));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(0, input2.read(buf, maxSize));
+
+ maxSize = 3;
+ pp::Input input3(count, str, NULL);
+ EXPECT_EQ(3, input3.read(buf, maxSize));
+ EXPECT_STREQ("foo", buf);
+ EXPECT_EQ(0, input3.read(buf, maxSize));
+
+ maxSize = 4;
+ pp::Input input4(count, str, NULL);
+ EXPECT_EQ(3, input4.read(buf, maxSize));
+ EXPECT_STREQ("foo", buf);
+ EXPECT_EQ(0, input4.read(buf, maxSize));
+}
+
+TEST(InputTest, ReadMultipleStrings)
+{
+ int count = 3;
+ const char* str[] = {"f", "o", "o"};
+ char buf[4] = {'\0', '\0', '\0', '\0'};
+
+ int maxSize = 1;
+ pp::Input input1(count, str, NULL);
+ EXPECT_EQ(1, input1.read(buf, maxSize));
+ EXPECT_EQ('f', buf[0]);
+ EXPECT_EQ(1, input1.read(buf, maxSize));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(1, input1.read(buf, maxSize));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(0, input1.read(buf, maxSize));
+
+ maxSize = 2;
+ pp::Input input2(count, str, NULL);
+ EXPECT_EQ(2, input2.read(buf, maxSize));
+ EXPECT_STREQ("fo", buf);
+ EXPECT_EQ(1, input2.read(buf, maxSize));
+ EXPECT_EQ('o', buf[0]);
+ EXPECT_EQ(0, input2.read(buf, maxSize));
+
+ maxSize = 3;
+ pp::Input input3(count, str, NULL);
+ EXPECT_EQ(3, input3.read(buf, maxSize));
+ EXPECT_STREQ("foo", buf);
+ EXPECT_EQ(0, input3.read(buf, maxSize));
+
+ maxSize = 4;
+ pp::Input input4(count, str, NULL);
+ EXPECT_EQ(3, input4.read(buf, maxSize));
+ EXPECT_STREQ("foo", buf);
+ EXPECT_EQ(0, input4.read(buf, maxSize));
+}
+
+TEST(InputTest, ReadStringsWithLength)
+{
+ int count = 2;
+ const char* str[] = {"foo", "bar"};
+ // Note that the length for the first string is 2 which is less than
+ // strlen(str[0]. We want to make sure that the last character is ignored.
+ int length[] = {2, 3};
+ char buf[6] = {'\0', '\0', '\0', '\0', '\0', '\0'};
+ int maxSize = 5;
+
+ pp::Input input(count, str, length);
+ EXPECT_EQ(maxSize, input.read(buf, maxSize));
+ EXPECT_STREQ("fobar", buf);
+}
+
diff --git a/tests/preprocessor_tests/location_test.cpp b/tests/preprocessor_tests/location_test.cpp
new file mode 100644
index 00000000..b615f99c
--- /dev/null
+++ b/tests/preprocessor_tests/location_test.cpp
@@ -0,0 +1,303 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class LocationTest : public PreprocessorTest
+{
+protected:
+ void expectLocation(int count,
+ const char* const string[],
+ const int length[],
+ const pp::SourceLocation& location)
+ {
+ ASSERT_TRUE(mPreprocessor.init(count, string, length));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+
+ EXPECT_EQ(location.file, token.location.file);
+ EXPECT_EQ(location.line, token.location.line);
+ }
+};
+
+TEST_F(LocationTest, String0_Line1)
+{
+ const char* str = "foo";
+ pp::SourceLocation loc(0, 1);
+
+ SCOPED_TRACE("String0_Line1");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, String0_Line2)
+{
+ const char* str = "\nfoo";
+ pp::SourceLocation loc(0, 2);
+
+ SCOPED_TRACE("String0_Line2");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, String1_Line1)
+{
+ const char* const str[] = {"\n\n", "foo"};
+ pp::SourceLocation loc(1, 1);
+
+ SCOPED_TRACE("String1_Line1");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, String1_Line2)
+{
+ const char* const str[] = {"\n\n", "\nfoo"};
+ pp::SourceLocation loc(1, 2);
+
+ SCOPED_TRACE("String1_Line2");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, NewlineInsideCommentCounted)
+{
+ const char* str = "/*\n\n*/foo";
+ pp::SourceLocation loc(0, 3);
+
+ SCOPED_TRACE("NewlineInsideCommentCounted");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, ErrorLocationAfterComment)
+{
+ const char* str = "/*\n\n*/@";
+
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::INVALID_CHARACTER,
+ pp::SourceLocation(0, 3),
+ "@"));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+// The location of a token straddling two or more strings is that of the
+// first character of the token.
+
+TEST_F(LocationTest, TokenStraddlingTwoStrings)
+{
+ const char* const str[] = {"f", "oo"};
+ pp::SourceLocation loc(0, 1);
+
+ SCOPED_TRACE("TokenStraddlingTwoStrings");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, TokenStraddlingThreeStrings)
+{
+ const char* const str[] = {"f", "o", "o"};
+ pp::SourceLocation loc(0, 1);
+
+ SCOPED_TRACE("TokenStraddlingThreeStrings");
+ expectLocation(3, str, NULL, loc);
+}
+
+TEST_F(LocationTest, EndOfFileWithoutNewline)
+{
+ const char* const str[] = {"foo"};
+ ASSERT_TRUE(mPreprocessor.init(1, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+}
+
+TEST_F(LocationTest, EndOfFileAfterNewline)
+{
+ const char* const str[] = {"foo\n"};
+ ASSERT_TRUE(mPreprocessor.init(1, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(2, token.location.line);
+}
+
+TEST_F(LocationTest, EndOfFileAfterEmptyString)
+{
+ const char* const str[] = {"foo\n", "\n", ""};
+ ASSERT_TRUE(mPreprocessor.init(3, str, NULL));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::LAST, token.type);
+ EXPECT_EQ(2, token.location.file);
+ EXPECT_EQ(1, token.location.line);
+}
+
+TEST_F(LocationTest, ValidLineDirective1)
+{
+ const char* str = "#line 10\n"
+ "foo";
+ pp::SourceLocation loc(0, 10);
+
+ SCOPED_TRACE("ValidLineDirective1");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, ValidLineDirective2)
+{
+ const char* str = "#line 10 20\n"
+ "foo";
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("ValidLineDirective2");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveCommentsIgnored)
+{
+ const char* str = "/* bar */"
+ "#"
+ "/* bar */"
+ "line"
+ "/* bar */"
+ "10"
+ "/* bar */"
+ "20"
+ "/* bar */"
+ "// bar "
+ "\n"
+ "foo";
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("LineDirectiveCommentsIgnored");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveWithMacro1)
+{
+ const char* str = "#define L 10\n"
+ "#define F(x) x\n"
+ "#line L F(20)\n"
+ "foo";
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("LineDirectiveWithMacro1");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveWithMacro2)
+{
+ const char* str = "#define LOC 10 20\n"
+ "#line LOC\n"
+ "foo";
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("LineDirectiveWithMacro2");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveWithPredefinedMacro)
+{
+ const char* str = "#line __LINE__ __FILE__\n"
+ "foo";
+ pp::SourceLocation loc(0, 1);
+
+ SCOPED_TRACE("LineDirectiveWithMacro");
+ expectLocation(1, &str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveNewlineBeforeStringBreak)
+{
+ const char* const str[] = {"#line 10 20\n", "foo"};
+ // String number is incremented after it is set by the line directive.
+ // Also notice that line number is reset after the string break.
+ pp::SourceLocation loc(21, 1);
+
+ SCOPED_TRACE("LineDirectiveNewlineBeforeStringBreak");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveNewlineAfterStringBreak)
+{
+ const char* const str[] = {"#line 10 20", "\nfoo"};
+ // String number is incremented before it is set by the line directive.
+ pp::SourceLocation loc(20, 10);
+
+ SCOPED_TRACE("LineDirectiveNewlineAfterStringBreak");
+ expectLocation(2, str, NULL, loc);
+}
+
+TEST_F(LocationTest, LineDirectiveMissingNewline)
+{
+ const char* str = "#line 10";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::EOF_IN_DIRECTIVE, _, _));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+struct LineTestParam
+{
+ const char* str;
+ pp::Diagnostics::ID id;
+};
+
+class InvalidLineTest : public LocationTest,
+ public testing::WithParamInterface<LineTestParam>
+{
+};
+
+TEST_P(InvalidLineTest, Identified)
+{
+ LineTestParam param = GetParam();
+ ASSERT_TRUE(mPreprocessor.init(1, &param.str, NULL));
+
+ using testing::_;
+ // Invalid line directive call.
+ EXPECT_CALL(mDiagnostics, print(param.id, pp::SourceLocation(0, 1), _));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+static const LineTestParam kParams[] = {
+ {"#line\n", pp::Diagnostics::INVALID_LINE_DIRECTIVE},
+ {"#line foo\n", pp::Diagnostics::INVALID_LINE_NUMBER},
+ {"#line 10 foo\n", pp::Diagnostics::INVALID_FILE_NUMBER},
+ {"#line 10 20 foo\n", pp::Diagnostics::UNEXPECTED_TOKEN},
+ {"#line 0xffffffff\n", pp::Diagnostics::INTEGER_OVERFLOW},
+ {"#line 10 0xffffffff\n", pp::Diagnostics::INTEGER_OVERFLOW}
+};
+
+INSTANTIATE_TEST_CASE_P(All, InvalidLineTest, testing::ValuesIn(kParams));
diff --git a/tests/preprocessor_tests/number_test.cpp b/tests/preprocessor_tests/number_test.cpp
new file mode 100644
index 00000000..13673212
--- /dev/null
+++ b/tests/preprocessor_tests/number_test.cpp
@@ -0,0 +1,170 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+#define CLOSED_RANGE(x, y) testing::Range(x, static_cast<char>((y) + 1))
+
+class InvalidNumberTest : public PreprocessorTest,
+ public testing::WithParamInterface<const char*>
+{
+};
+
+TEST_P(InvalidNumberTest, InvalidNumberIdentified)
+{
+ const char* str = GetParam();
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::INVALID_NUMBER, _, str));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+}
+
+INSTANTIATE_TEST_CASE_P(InvalidIntegers, InvalidNumberTest,
+ testing::Values("1a", "08", "0xG"));
+
+
+INSTANTIATE_TEST_CASE_P(InvalidFloats, InvalidNumberTest,
+ testing::Values("1eg", "0.a", "0.1.2", ".0a", ".0.1"));
+
+typedef std::tr1::tuple<const char*, char> IntegerParams;
+class IntegerTest : public PreprocessorTest,
+ public testing::WithParamInterface<IntegerParams>
+{
+};
+
+TEST_P(IntegerTest, Identified)
+{
+ std::string str(std::tr1::get<0>(GetParam())); // prefix.
+ str.push_back(std::tr1::get<1>(GetParam())); // digit.
+ const char* cstr = str.c_str();
+
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_INT, token.type);
+ EXPECT_EQ(str, token.text);
+}
+
+INSTANTIATE_TEST_CASE_P(DecimalInteger,
+ IntegerTest,
+ testing::Combine(testing::Values(""),
+ CLOSED_RANGE('0', '9')));
+
+INSTANTIATE_TEST_CASE_P(OctalInteger,
+ IntegerTest,
+ testing::Combine(testing::Values("0"),
+ CLOSED_RANGE('0', '7')));
+
+INSTANTIATE_TEST_CASE_P(HexadecimalInteger_0_9,
+ IntegerTest,
+ testing::Combine(testing::Values("0x", "0X"),
+ CLOSED_RANGE('0', '9')));
+
+INSTANTIATE_TEST_CASE_P(HexadecimalInteger_a_f,
+ IntegerTest,
+ testing::Combine(testing::Values("0x", "0X"),
+ CLOSED_RANGE('a', 'f')));
+
+INSTANTIATE_TEST_CASE_P(HexadecimalInteger_A_F,
+ IntegerTest,
+ testing::Combine(testing::Values("0x", "0X"),
+ CLOSED_RANGE('A', 'F')));
+
+class FloatTest : public PreprocessorTest
+{
+ protected:
+ void expectFloat(const std::string& str)
+ {
+ const char* cstr = str.c_str();
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::CONST_FLOAT, token.type);
+ EXPECT_EQ(str, token.text);
+ }
+};
+
+typedef std::tr1::tuple<char, char, const char*, char> FloatScientificParams;
+class FloatScientificTest :
+ public FloatTest,
+ public testing::WithParamInterface<FloatScientificParams>
+{
+};
+
+// This test covers floating point numbers of form [0-9][eE][+-]?[0-9].
+TEST_P(FloatScientificTest, FloatIdentified)
+{
+ std::string str;
+ str.push_back(std::tr1::get<0>(GetParam())); // significand [0-9].
+ str.push_back(std::tr1::get<1>(GetParam())); // separator [eE].
+ str.append(std::tr1::get<2>(GetParam())); // sign [" " "+" "-"].
+ str.push_back(std::tr1::get<3>(GetParam())); // exponent [0-9].
+
+ SCOPED_TRACE("FloatScientificTest");
+ expectFloat(str);
+}
+
+INSTANTIATE_TEST_CASE_P(FloatScientific,
+ FloatScientificTest,
+ testing::Combine(CLOSED_RANGE('0', '9'),
+ testing::Values('e', 'E'),
+ testing::Values("", "+", "-"),
+ CLOSED_RANGE('0', '9')));
+
+typedef std::tr1::tuple<char, char> FloatFractionParams;
+class FloatFractionTest :
+ public FloatTest,
+ public testing::WithParamInterface<FloatFractionParams>
+{
+};
+
+// This test covers floating point numbers of form [0-9]"." and [0-9]?"."[0-9].
+TEST_P(FloatFractionTest, FloatIdentified)
+{
+ std::string str;
+
+ char significand = std::tr1::get<0>(GetParam());
+ if (significand != '\0')
+ str.push_back(significand);
+
+ str.push_back('.');
+
+ char fraction = std::tr1::get<1>(GetParam());
+ if (fraction != '\0')
+ str.push_back(fraction);
+
+ SCOPED_TRACE("FloatFractionTest");
+ expectFloat(str);
+}
+
+INSTANTIATE_TEST_CASE_P(FloatFraction_X_X,
+ FloatFractionTest,
+ testing::Combine(CLOSED_RANGE('0', '9'),
+ CLOSED_RANGE('0', '9')));
+
+INSTANTIATE_TEST_CASE_P(FloatFraction_0_X,
+ FloatFractionTest,
+ testing::Combine(testing::Values('\0'),
+ CLOSED_RANGE('0', '9')));
+
+INSTANTIATE_TEST_CASE_P(FloatFraction_X_0,
+ FloatFractionTest,
+ testing::Combine(CLOSED_RANGE('0', '9'),
+ testing::Values('\0')));
+
+// In the tests above we have tested individual parts of a float separately.
+// This test has all parts of a float.
+TEST_F(FloatTest, FractionScientific)
+{
+ SCOPED_TRACE("FractionScientific");
+ expectFloat("0.1e+2");
+}
diff --git a/tests/preprocessor_tests/operator_test.cpp b/tests/preprocessor_tests/operator_test.cpp
new file mode 100644
index 00000000..d73bec63
--- /dev/null
+++ b/tests/preprocessor_tests/operator_test.cpp
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+struct OperatorTestParam
+{
+ const char* str;
+ int op;
+};
+
+class OperatorTest : public PreprocessorTest,
+ public testing::WithParamInterface<OperatorTestParam>
+{
+};
+
+TEST_P(OperatorTest, Identified)
+{
+ OperatorTestParam param = GetParam();
+
+ ASSERT_TRUE(mPreprocessor.init(1, &param.str, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(param.op, token.type);
+ EXPECT_EQ(param.str, token.text);
+}
+
+static const OperatorTestParam kOperators[] = {
+ {"(", '('},
+ {")", ')'},
+ {"[", '['},
+ {"]", ']'},
+ {".", '.'},
+ {"+", '+'},
+ {"-", '-'},
+ {"~", '~'},
+ {"!", '!'},
+ {"*", '*'},
+ {"/", '/'},
+ {"%", '%'},
+ {"<", '<'},
+ {">", '>'},
+ {"&", '&'},
+ {"^", '^'},
+ {"|", '|'},
+ {"?", '?'},
+ {":", ':'},
+ {"=", '='},
+ {",", ','},
+ {"++", pp::Token::OP_INC},
+ {"--", pp::Token::OP_DEC},
+ {"<<", pp::Token::OP_LEFT},
+ {">>", pp::Token::OP_RIGHT},
+ {"<=", pp::Token::OP_LE},
+ {">=", pp::Token::OP_GE},
+ {"==", pp::Token::OP_EQ},
+ {"!=", pp::Token::OP_NE},
+ {"&&", pp::Token::OP_AND},
+ {"^^", pp::Token::OP_XOR},
+ {"||", pp::Token::OP_OR},
+ {"+=", pp::Token::OP_ADD_ASSIGN},
+ {"-=", pp::Token::OP_SUB_ASSIGN},
+ {"*=", pp::Token::OP_MUL_ASSIGN},
+ {"/=", pp::Token::OP_DIV_ASSIGN},
+ {"%=", pp::Token::OP_MOD_ASSIGN},
+ {"<<=", pp::Token::OP_LEFT_ASSIGN},
+ {">>=", pp::Token::OP_RIGHT_ASSIGN},
+ {"&=", pp::Token::OP_AND_ASSIGN},
+ {"^=", pp::Token::OP_XOR_ASSIGN},
+ {"|=", pp::Token::OP_OR_ASSIGN}
+};
+
+INSTANTIATE_TEST_CASE_P(All, OperatorTest,
+ testing::ValuesIn(kOperators));
+
diff --git a/tests/preprocessor_tests/pragma_test.cpp b/tests/preprocessor_tests/pragma_test.cpp
new file mode 100644
index 00000000..a76fadae
--- /dev/null
+++ b/tests/preprocessor_tests/pragma_test.cpp
@@ -0,0 +1,126 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class PragmaTest : public PreprocessorTest
+{
+};
+
+TEST_F(PragmaTest, EmptyName)
+{
+ const char* str = "#pragma\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ // No handlePragma calls.
+ EXPECT_CALL(mDirectiveHandler, handlePragma(_, _, _)).Times(0);
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, EmptyValue)
+{
+ const char* str = "#pragma foo\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(pp::SourceLocation(0, 1), "foo", ""));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, NameValue)
+{
+ const char* str = "#pragma foo(bar)\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(pp::SourceLocation(0, 1), "foo", "bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, Comments)
+{
+ const char* str = "/*foo*/"
+ "#"
+ "/*foo*/"
+ "pragma"
+ "/*foo*/"
+ "foo"
+ "/*foo*/"
+ "("
+ "/*foo*/"
+ "bar"
+ "/*foo*/"
+ ")"
+ "/*foo*/"
+ "//foo"
+ "\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(pp::SourceLocation(0, 1), "foo", "bar"));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(PragmaTest, MissingNewline)
+{
+ const char* str = "#pragma foo(bar)";
+ const char* expected = "";
+
+ using testing::_;
+ // Pragma successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handlePragma(pp::SourceLocation(0, 1), "foo", "bar"));
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::EOF_IN_DIRECTIVE, _, _));
+
+ preprocess(str, expected);
+}
+
+class InvalidPragmaTest : public PragmaTest,
+ public testing::WithParamInterface<const char*>
+{
+};
+
+TEST_P(InvalidPragmaTest, Identified)
+{
+ const char* str = GetParam();
+ const char* expected = "\n";
+
+ using testing::_;
+ // No handlePragma calls.
+ EXPECT_CALL(mDirectiveHandler, handlePragma(_, _, _)).Times(0);
+ // Unrecognized pragma warning.
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::UNRECOGNIZED_PRAGMA,
+ pp::SourceLocation(0, 1), _));
+
+ preprocess(str, expected);
+}
+
+INSTANTIATE_TEST_CASE_P(All, InvalidPragmaTest, testing::Values(
+ "#pragma 1\n", // Invalid name.
+ "#pragma foo()\n", // Missing value.
+ "#pragma foo bar)\n", // Missing left paren,
+ "#pragma foo(bar\n", // Missing right paren.
+ "#pragma foo bar\n", // Missing parens.
+ "#pragma foo(bar) baz\n")); // Extra tokens.
diff --git a/tests/preprocessor_tests/space_test.cpp b/tests/preprocessor_tests/space_test.cpp
new file mode 100644
index 00000000..c6b70c56
--- /dev/null
+++ b/tests/preprocessor_tests/space_test.cpp
@@ -0,0 +1,106 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class SpaceTest : public PreprocessorTest
+{
+ protected:
+ void expectSpace(const std::string& str)
+ {
+ const char* cstr = str.c_str();
+ ASSERT_TRUE(mPreprocessor.init(1, &cstr, 0));
+
+ pp::Token token;
+ // "foo" is returned after ignoring the whitespace characters.
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ // The whitespace character is however recorded with the next token.
+ EXPECT_TRUE(token.hasLeadingSpace());
+ }
+};
+
+// Whitespace characters allowed in GLSL.
+// Note that newline characters (\n) will be tested separately.
+static const char kSpaceChars[] = {' ', '\t', '\v', '\f'};
+
+// This test fixture tests the processing of a single whitespace character.
+// All tests in this fixture are ran with all possible whitespace character
+// allowed in GLSL.
+class SpaceCharTest : public SpaceTest,
+ public testing::WithParamInterface<char>
+{
+};
+
+TEST_P(SpaceCharTest, SpaceIgnored)
+{
+ // Construct test string with the whitespace char before "foo".
+ std::string str(1, GetParam());
+ str.append("foo");
+
+ expectSpace(str);
+}
+
+INSTANTIATE_TEST_CASE_P(SingleSpaceChar,
+ SpaceCharTest,
+ testing::ValuesIn(kSpaceChars));
+
+// This test fixture tests the processing of a string containing consecutive
+// whitespace characters. All tests in this fixture are ran with all possible
+// combinations of whitespace characters allowed in GLSL.
+typedef std::tr1::tuple<char, char, char> SpaceStringParams;
+class SpaceStringTest : public SpaceTest,
+ public testing::WithParamInterface<SpaceStringParams>
+{
+};
+
+TEST_P(SpaceStringTest, SpaceIgnored)
+{
+ // Construct test string with the whitespace char before "foo".
+ std::string str;
+ str.push_back(std::tr1::get<0>(GetParam()));
+ str.push_back(std::tr1::get<1>(GetParam()));
+ str.push_back(std::tr1::get<2>(GetParam()));
+ str.append("foo");
+
+ expectSpace(str);
+}
+
+INSTANTIATE_TEST_CASE_P(SpaceCharCombination,
+ SpaceStringTest,
+ testing::Combine(testing::ValuesIn(kSpaceChars),
+ testing::ValuesIn(kSpaceChars),
+ testing::ValuesIn(kSpaceChars)));
+
+// The tests above make sure that the space char is recorded in the
+// next token. This test makes sure that a token is not incorrectly marked
+// to have leading space.
+TEST_F(SpaceTest, LeadingSpace)
+{
+ const char* str = " foo+ -bar";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, 0));
+
+ pp::Token token;
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("foo", token.text);
+ EXPECT_TRUE(token.hasLeadingSpace());
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ('+', token.type);
+ EXPECT_FALSE(token.hasLeadingSpace());
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ('-', token.type);
+ EXPECT_TRUE(token.hasLeadingSpace());
+
+ mPreprocessor.lex(&token);
+ EXPECT_EQ(pp::Token::IDENTIFIER, token.type);
+ EXPECT_EQ("bar", token.text);
+ EXPECT_FALSE(token.hasLeadingSpace());
+}
diff --git a/tests/preprocessor_tests/token_test.cpp b/tests/preprocessor_tests/token_test.cpp
new file mode 100644
index 00000000..323d4683
--- /dev/null
+++ b/tests/preprocessor_tests/token_test.cpp
@@ -0,0 +1,90 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "gtest/gtest.h"
+
+#include "Token.h"
+
+TEST(TokenTest, DefaultConstructor)
+{
+ pp::Token token;
+ EXPECT_EQ(0, token.type);
+ EXPECT_EQ(0, token.flags);
+ EXPECT_EQ(0, token.location.line);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ("", token.text);
+}
+
+TEST(TokenTest, Assignment)
+{
+ pp::Token token;
+ token.type = 1;
+ token.flags = 1;
+ token.location.line = 1;
+ token.location.file = 1;
+ token.text.assign("foo");
+
+ token = pp::Token();
+ EXPECT_EQ(0, token.type);
+ EXPECT_EQ(0, token.flags);
+ EXPECT_EQ(0, token.location.line);
+ EXPECT_EQ(0, token.location.file);
+ EXPECT_EQ("", token.text);
+}
+
+TEST(TokenTest, Equals)
+{
+ pp::Token token;
+ EXPECT_TRUE(token.equals(pp::Token()));
+
+ token.type = 1;
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.type = 0;
+
+ token.flags = 1;
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.flags = 0;
+
+ token.location.line = 1;
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.location.line = 0;
+
+ token.location.file = 1;
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.location.file = 0;
+
+ token.text.assign("foo");
+ EXPECT_FALSE(token.equals(pp::Token()));
+ token.text.clear();
+
+ EXPECT_TRUE(token.equals(pp::Token()));
+}
+
+TEST(TokenTest, HasLeadingSpace)
+{
+ pp::Token token;
+ EXPECT_FALSE(token.hasLeadingSpace());
+ token.setHasLeadingSpace(true);
+ EXPECT_TRUE(token.hasLeadingSpace());
+ token.setHasLeadingSpace(false);
+ EXPECT_FALSE(token.hasLeadingSpace());
+}
+
+TEST(TokenTest, Write)
+{
+ pp::Token token;
+ token.text.assign("foo");
+ std::stringstream out1;
+ out1 << token;
+ EXPECT_TRUE(out1.good());
+ EXPECT_EQ("foo", out1.str());
+
+ token.setHasLeadingSpace(true);
+ std::stringstream out2;
+ out2 << token;
+ EXPECT_TRUE(out2.good());
+ EXPECT_EQ(" foo", out2.str());
+}
diff --git a/tests/preprocessor_tests/version_test.cpp b/tests/preprocessor_tests/version_test.cpp
new file mode 100644
index 00000000..0db2fad1
--- /dev/null
+++ b/tests/preprocessor_tests/version_test.cpp
@@ -0,0 +1,229 @@
+//
+// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "PreprocessorTest.h"
+#include "Token.h"
+
+class VersionTest : public PreprocessorTest
+{
+};
+
+TEST_F(VersionTest, Valid)
+{
+ const char* str = "#version 200\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 1), 200));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, CommentsIgnored)
+{
+ const char* str = "/*foo*/"
+ "#"
+ "/*foo*/"
+ "version"
+ "/*foo*/"
+ "200"
+ "/*foo*/"
+ "//foo"
+ "\n";
+ const char* expected = "\n";
+
+ using testing::_;
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 1), 200));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, MissingNewline)
+{
+ const char* str = "#version 200";
+ const char* expected = "";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 1), 200));
+ // Error reported about EOF.
+ EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::EOF_IN_DIRECTIVE, _, _));
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, AfterComments)
+{
+ const char* str = "/* block comment acceptable */\n"
+ "// line comment acceptable\n"
+ "#version 200\n";
+ const char* expected = "\n\n\n";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 3), 200));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, AfterWhitespace)
+{
+ const char* str = "\n"
+ "\n"
+ "#version 200\n";
+ const char* expected = "\n\n\n";
+
+ using testing::_;
+ // Directive successfully parsed.
+ EXPECT_CALL(mDirectiveHandler,
+ handleVersion(pp::SourceLocation(0, 3), 200));
+ // No error or warning.
+ EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
+
+ preprocess(str, expected);
+}
+
+TEST_F(VersionTest, AfterValidToken)
+{
+ const char* str = "foo\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 2), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+TEST_F(VersionTest, AfterInvalidToken)
+{
+ const char* str = "$\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::INVALID_CHARACTER,
+ pp::SourceLocation(0, 1), "$"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 2), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+TEST_F(VersionTest, AfterValidDirective)
+{
+ const char* str = "#\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 2), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+TEST_F(VersionTest, AfterInvalidDirective)
+{
+ const char* str = "#foo\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::DIRECTIVE_INVALID_NAME,
+ pp::SourceLocation(0, 1), "foo"));
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 2), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+TEST_F(VersionTest, AfterExcludedBlock)
+{
+ const char* str = "#if 0\n"
+ "foo\n"
+ "#endif\n"
+ "#version 200\n";
+ ASSERT_TRUE(mPreprocessor.init(1, &str, NULL));
+
+ using testing::_;
+ EXPECT_CALL(mDiagnostics,
+ print(pp::Diagnostics::VERSION_NOT_FIRST_STATEMENT,
+ pp::SourceLocation(0, 4), _));
+
+ pp::Token token;
+ do
+ {
+ mPreprocessor.lex(&token);
+ } while (token.type != pp::Token::LAST);
+}
+
+struct VersionTestParam
+{
+ const char* str;
+ pp::Diagnostics::ID id;
+};
+
+class InvalidVersionTest : public VersionTest,
+ public testing::WithParamInterface<VersionTestParam>
+{
+};
+
+TEST_P(InvalidVersionTest, Identified)
+{
+ VersionTestParam param = GetParam();
+ const char* expected = "\n";
+
+ using testing::_;
+ // No handleVersion call.
+ EXPECT_CALL(mDirectiveHandler, handleVersion(_, _)).Times(0);
+ // Invalid version directive call.
+ EXPECT_CALL(mDiagnostics, print(param.id, pp::SourceLocation(0, 1), _));
+
+ preprocess(param.str, expected);
+}
+
+static const VersionTestParam kParams[] = {
+ {"#version\n", pp::Diagnostics::INVALID_VERSION_DIRECTIVE},
+ {"#version foo\n", pp::Diagnostics::INVALID_VERSION_NUMBER},
+ {"#version 100 foo\n", pp::Diagnostics::UNEXPECTED_TOKEN},
+ {"#version 0xffffffff\n", pp::Diagnostics::INTEGER_OVERFLOW}
+};
+
+INSTANTIATE_TEST_CASE_P(All, InvalidVersionTest, testing::ValuesIn(kParams));