From e5b0d96b2716db408f9523a2d699f7cb3ab39832 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 21 Oct 2017 03:08:18 -0300 Subject: [PATCH] Restructured some Shader code. Added runtime temporary caching and sharing of shader stages. Resolves issue #1235. --HG-- branch : minor --- CMakeLists.txt | 4 + .../xcode/liblove.xcodeproj/project.pbxproj | 46 +++- src/modules/graphics/Graphics.cpp | 86 +++++++- src/modules/graphics/Graphics.h | 23 +- src/modules/graphics/Shader.cpp | 186 +--------------- src/modules/graphics/Shader.h | 37 +--- src/modules/graphics/ShaderStage.cpp | 205 ++++++++++++++++++ src/modules/graphics/ShaderStage.h | 99 +++++++++ src/modules/graphics/Texture.h | 8 - src/modules/graphics/opengl/Graphics.cpp | 15 +- src/modules/graphics/opengl/Graphics.h | 3 +- src/modules/graphics/opengl/Shader.cpp | 119 ++-------- src/modules/graphics/opengl/Shader.h | 8 +- src/modules/graphics/opengl/ShaderStage.cpp | 105 +++++++++ src/modules/graphics/opengl/ShaderStage.h | 55 +++++ src/modules/graphics/wrap_Graphics.cpp | 55 +++-- 16 files changed, 683 insertions(+), 371 deletions(-) create mode 100644 src/modules/graphics/ShaderStage.cpp create mode 100644 src/modules/graphics/ShaderStage.h create mode 100644 src/modules/graphics/opengl/ShaderStage.cpp create mode 100644 src/modules/graphics/opengl/ShaderStage.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f3aaf473..0fa733584 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -529,6 +529,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT src/modules/graphics/Quad.h src/modules/graphics/Shader.cpp src/modules/graphics/Shader.h + src/modules/graphics/ShaderStage.cpp + src/modules/graphics/ShaderStage.h src/modules/graphics/SpriteBatch.cpp src/modules/graphics/SpriteBatch.h src/modules/graphics/StreamBuffer.cpp @@ -588,6 +590,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_OPENGL src/modules/graphics/opengl/ParticleSystem.h src/modules/graphics/opengl/Shader.cpp src/modules/graphics/opengl/Shader.h + src/modules/graphics/opengl/ShaderStage.cpp + src/modules/graphics/opengl/ShaderStage.h src/modules/graphics/opengl/SpriteBatch.cpp src/modules/graphics/opengl/SpriteBatch.h src/modules/graphics/opengl/StreamBuffer.cpp diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 989677872..562ecda4f 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -821,9 +821,6 @@ FA27B39D1B498151008A9DCE /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B38A1B498151008A9DCE /* Video.cpp */; }; FA27B39E1B498151008A9DCE /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B38A1B498151008A9DCE /* Video.cpp */; }; FA27B39F1B498151008A9DCE /* Video.h in Headers */ = {isa = PBXBuildFile; fileRef = FA27B38B1B498151008A9DCE /* Video.h */; }; - FA27B3A01B498151008A9DCE /* VideoStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B38C1B498151008A9DCE /* VideoStream.cpp */; }; - FA27B3A11B498151008A9DCE /* VideoStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B38C1B498151008A9DCE /* VideoStream.cpp */; }; - FA27B3A21B498151008A9DCE /* VideoStream.h in Headers */ = {isa = PBXBuildFile; fileRef = FA27B38D1B498151008A9DCE /* VideoStream.h */; }; FA27B3A91B498151008A9DCE /* Video.h in Headers */ = {isa = PBXBuildFile; fileRef = FA27B3931B498151008A9DCE /* Video.h */; }; FA27B3AA1B498151008A9DCE /* VideoStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B3941B498151008A9DCE /* VideoStream.cpp */; }; FA27B3AB1B498151008A9DCE /* VideoStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B3941B498151008A9DCE /* VideoStream.cpp */; }; @@ -843,6 +840,12 @@ FA2AF6741DAD64970032B62C /* vertex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA2AF6731DAD64970032B62C /* vertex.cpp */; }; FA2AF6751DAD64970032B62C /* vertex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA2AF6731DAD64970032B62C /* vertex.cpp */; }; FA317EBA18F28B6D00B0BCD7 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA317EB918F28B6D00B0BCD7 /* libz.dylib */; }; + FA3C5E421F8C368C0003C579 /* ShaderStage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA3C5E401F8C368C0003C579 /* ShaderStage.cpp */; }; + FA3C5E431F8C368C0003C579 /* ShaderStage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA3C5E401F8C368C0003C579 /* ShaderStage.cpp */; }; + FA3C5E441F8C368C0003C579 /* ShaderStage.h in Headers */ = {isa = PBXBuildFile; fileRef = FA3C5E411F8C368C0003C579 /* ShaderStage.h */; }; + FA3C5E471F8D80CA0003C579 /* ShaderStage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA3C5E451F8D80CA0003C579 /* ShaderStage.cpp */; }; + FA3C5E481F8D80CA0003C579 /* ShaderStage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA3C5E451F8D80CA0003C579 /* ShaderStage.cpp */; }; + FA3C5E491F8D80CA0003C579 /* ShaderStage.h in Headers */ = {isa = PBXBuildFile; fileRef = FA3C5E461F8D80CA0003C579 /* ShaderStage.h */; }; FA41A3C81C0A1F950084430C /* ASTCHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */; }; FA41A3C91C0A1F950084430C /* ASTCHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */; }; FA41A3CA1C0A1F950084430C /* ASTCHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA41A3C71C0A1F950084430C /* ASTCHandler.h */; }; @@ -963,6 +966,10 @@ FAA3A9AE1B7D465A00CED060 /* android.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAA3A9AC1B7D465A00CED060 /* android.cpp */; }; FAA3A9AF1B7D465A00CED060 /* android.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAA3A9AC1B7D465A00CED060 /* android.cpp */; }; FAA3A9B01B7D465A00CED060 /* android.h in Headers */ = {isa = PBXBuildFile; fileRef = FAA3A9AD1B7D465A00CED060 /* android.h */; }; + FAA54ACA1F91660400A8FA7B /* OggDemuxer.h in Headers */ = {isa = PBXBuildFile; fileRef = FAA54AC61F91660400A8FA7B /* OggDemuxer.h */; }; + FAA54ACB1F91660400A8FA7B /* TheoraVideoStream.h in Headers */ = {isa = PBXBuildFile; fileRef = FAA54AC71F91660400A8FA7B /* TheoraVideoStream.h */; }; + FAA54ACC1F91660400A8FA7B /* TheoraVideoStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAA54AC81F91660400A8FA7B /* TheoraVideoStream.cpp */; }; + FAA54ACD1F91660400A8FA7B /* OggDemuxer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAA54AC91F91660400A8FA7B /* OggDemuxer.cpp */; }; FAA627CE18E7E1560080752D /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAA627CD18E7E1560080752D /* CoreServices.framework */; }; FAAA3FD81F64B3AD00F89E99 /* lprefix.h in Headers */ = {isa = PBXBuildFile; fileRef = FAAA3FD31F64B3AD00F89E99 /* lprefix.h */; }; FAAA3FD91F64B3AD00F89E99 /* lstrlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FAAA3FD41F64B3AD00F89E99 /* lstrlib.c */; }; @@ -1737,8 +1744,6 @@ FA1E88821DF363DB00E808AA /* Filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Filter.h; sourceTree = ""; }; FA27B38A1B498151008A9DCE /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Video.cpp; sourceTree = ""; }; FA27B38B1B498151008A9DCE /* Video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Video.h; sourceTree = ""; }; - FA27B38C1B498151008A9DCE /* VideoStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VideoStream.cpp; sourceTree = ""; }; - FA27B38D1B498151008A9DCE /* VideoStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoStream.h; sourceTree = ""; }; FA27B3931B498151008A9DCE /* Video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Video.h; sourceTree = ""; }; FA27B3941B498151008A9DCE /* VideoStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VideoStream.cpp; sourceTree = ""; }; FA27B3951B498151008A9DCE /* VideoStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoStream.h; sourceTree = ""; }; @@ -1757,6 +1762,10 @@ FA2AF6731DAD64970032B62C /* vertex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vertex.cpp; sourceTree = ""; }; FA2E9BFE1C19E00C0004A1EE /* wrap_RandomGenerator.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = wrap_RandomGenerator.lua; sourceTree = ""; }; FA317EB918F28B6D00B0BCD7 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + FA3C5E401F8C368C0003C579 /* ShaderStage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ShaderStage.cpp; sourceTree = ""; }; + FA3C5E411F8C368C0003C579 /* ShaderStage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShaderStage.h; sourceTree = ""; }; + FA3C5E451F8D80CA0003C579 /* ShaderStage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ShaderStage.cpp; sourceTree = ""; }; + FA3C5E461F8D80CA0003C579 /* ShaderStage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShaderStage.h; sourceTree = ""; }; FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = ASTCHandler.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; FA41A3C71C0A1F950084430C /* ASTCHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASTCHandler.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; FA4B66C81ABBCF1900558F15 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = ""; }; @@ -1835,6 +1844,10 @@ FA9D8DDF1DEF843D002CD881 /* Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = ""; }; FAA3A9AC1B7D465A00CED060 /* android.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = android.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; FAA3A9AD1B7D465A00CED060 /* android.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = android.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + FAA54AC61F91660400A8FA7B /* OggDemuxer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OggDemuxer.h; sourceTree = ""; }; + FAA54AC71F91660400A8FA7B /* TheoraVideoStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TheoraVideoStream.h; sourceTree = ""; }; + FAA54AC81F91660400A8FA7B /* TheoraVideoStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TheoraVideoStream.cpp; sourceTree = ""; }; + FAA54AC91F91660400A8FA7B /* OggDemuxer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OggDemuxer.cpp; sourceTree = ""; }; FAA627CD18E7E1560080752D /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; FAAA3FD31F64B3AD00F89E99 /* lprefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lprefix.h; sourceTree = ""; }; FAAA3FD41F64B3AD00F89E99 /* lstrlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lstrlib.c; sourceTree = ""; }; @@ -2705,6 +2718,8 @@ FA0B7BBD1A95902C000E1D17 /* Quad.h */, FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */, FA1BA0B01E16FD0800AA2803 /* Shader.h */, + FA3C5E401F8C368C0003C579 /* ShaderStage.cpp */, + FA3C5E411F8C368C0003C579 /* ShaderStage.h */, FADF542D1E3DABF600012CC0 /* SpriteBatch.cpp */, FADF542E1E3DABF600012CC0 /* SpriteBatch.h */, FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */, @@ -2770,6 +2785,8 @@ FA0B7B9A1A95902C000E1D17 /* ParticleSystem.h */, FA0B7B9D1A95902C000E1D17 /* Shader.cpp */, FA0B7B9E1A95902C000E1D17 /* Shader.h */, + FA3C5E451F8D80CA0003C579 /* ShaderStage.cpp */, + FA3C5E461F8D80CA0003C579 /* ShaderStage.h */, FA0B7B9F1A95902C000E1D17 /* SpriteBatch.cpp */, FA0B7BA01A95902C000E1D17 /* SpriteBatch.h */, FA7634481E28722A0066EF9E /* StreamBuffer.cpp */, @@ -3244,10 +3261,12 @@ FA27B3891B498151008A9DCE /* theora */ = { isa = PBXGroup; children = ( + FAA54AC91F91660400A8FA7B /* OggDemuxer.cpp */, + FAA54AC61F91660400A8FA7B /* OggDemuxer.h */, + FAA54AC81F91660400A8FA7B /* TheoraVideoStream.cpp */, + FAA54AC71F91660400A8FA7B /* TheoraVideoStream.h */, FA27B38A1B498151008A9DCE /* Video.cpp */, FA27B38B1B498151008A9DCE /* Video.h */, - FA27B38C1B498151008A9DCE /* VideoStream.cpp */, - FA27B38D1B498151008A9DCE /* VideoStream.h */, ); path = theora; sourceTree = ""; @@ -3622,6 +3641,7 @@ FADF54361E3DAE6E00012CC0 /* wrap_SpriteBatch.h in Headers */, FA0B7DB01A95902C000E1D17 /* wrap_CompressedImageData.h in Headers */, FA0B7AC11A958EA3000E1D17 /* callbacks.h in Headers */, + FA3C5E491F8D80CA0003C579 /* ShaderStage.h in Headers */, FA0B7D8F1A95902C000E1D17 /* ddsHandler.h in Headers */, FAB2D5AC1AABDD8A008224A4 /* TrueTypeRasterizer.h in Headers */, FAF140C41E20934C00F898D2 /* ShaderLang.h in Headers */, @@ -3658,6 +3678,7 @@ FA0B7CE41A95902C000E1D17 /* wrap_Audio.h in Headers */, FA0B7A7F1A958EA3000E1D17 /* b2ContactSolver.h in Headers */, FADF540F1E3D7CDD00012CC0 /* wrap_Video.h in Headers */, + FAA54ACA1F91660400A8FA7B /* OggDemuxer.h in Headers */, FA0B79491A958E3B000E1D17 /* version.h in Headers */, FAF140581E20934C00F898D2 /* BaseTypes.h in Headers */, FA0B7B2B1A958EA3000E1D17 /* stb_image.h in Headers */, @@ -3783,9 +3804,9 @@ FA0B7E961A95902C000E1D17 /* Mpg123Decoder.h in Headers */, FADF54091E3D78F700012CC0 /* Video.h in Headers */, FA0B7D501A95902C000E1D17 /* SpriteBatch.h in Headers */, + FAA54ACB1F91660400A8FA7B /* TheoraVideoStream.h in Headers */, FA0B7DD51A95902C000E1D17 /* BezierCurve.h in Headers */, FA0B79271A958E3B000E1D17 /* int.h in Headers */, - FA27B3A21B498151008A9DCE /* VideoStream.h in Headers */, FA0B7E531A95902C000E1D17 /* wrap_FrictionJoint.h in Headers */, FA0B7EB71A95902C000E1D17 /* wrap_System.h in Headers */, FA27B3A91B498151008A9DCE /* Video.h in Headers */, @@ -3878,6 +3899,7 @@ 217DFBF81D9F6D490055D849 /* pierror.h in Headers */, 217DFC021D9F6D490055D849 /* tcp.h in Headers */, FA0B7A3D1A958EA3000E1D17 /* b2TimeOfImpact.h in Headers */, + FA3C5E441F8C368C0003C579 /* ShaderStage.h in Headers */, FA0B79261A958E3B000E1D17 /* Exception.h in Headers */, FA0B7D4D1A95902C000E1D17 /* Shader.h in Headers */, FA0B793D1A958E3B000E1D17 /* runtime.h in Headers */, @@ -4093,6 +4115,7 @@ FA4F2C031DE936C200CA37D7 /* auxiliar.c in Sources */, FA0B7E731A95902C000E1D17 /* wrap_Shape.cpp in Sources */, FA0B7CFE1A95902C000E1D17 /* File.cpp in Sources */, + FA3C5E481F8D80CA0003C579 /* ShaderStage.cpp in Sources */, FA27B39E1B498151008A9DCE /* Video.cpp in Sources */, FA0B7A751A958EA3000E1D17 /* b2ChainAndPolygonContact.cpp in Sources */, FA0B7E6A1A95902C000E1D17 /* wrap_PulleyJoint.cpp in Sources */, @@ -4128,6 +4151,7 @@ FAF140AA1E20934C00F898D2 /* SymbolTable.cpp in Sources */, FA0B7A8D1A958EA3000E1D17 /* b2DistanceJoint.cpp in Sources */, FA0B7A841A958EA3000E1D17 /* b2EdgeAndPolygonContact.cpp in Sources */, + FA3C5E431F8C368C0003C579 /* ShaderStage.cpp in Sources */, FA0B7E191A95902C000E1D17 /* MotorJoint.cpp in Sources */, FAF1406F1E20934C00F898D2 /* Initialize.cpp in Sources */, FA0B7E4F1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */, @@ -4252,7 +4276,6 @@ FA0B791C1A958E3B000E1D17 /* b64.cpp in Sources */, FA1E88851DF363E100E808AA /* Filter.cpp in Sources */, FA0B7DA01A95902C000E1D17 /* KTXHandler.cpp in Sources */, - FA27B3A11B498151008A9DCE /* VideoStream.cpp in Sources */, FA0B7A5C1A958EA3000E1D17 /* b2Timer.cpp in Sources */, FA0B7CEC1A95902C000E1D17 /* Event.cpp in Sources */, FA27B3AB1B498151008A9DCE /* VideoStream.cpp in Sources */, @@ -4428,6 +4451,7 @@ FA0B7D2B1A95902C000E1D17 /* wrap_Rasterizer.cpp in Sources */, FA0B7E8E1A95902C000E1D17 /* GmeDecoder.cpp in Sources */, FA0B7CD61A95902C000E1D17 /* Audio.cpp in Sources */, + FA3C5E421F8C368C0003C579 /* ShaderStage.cpp in Sources */, FA0B7A9E1A958EA3000E1D17 /* b2PrismaticJoint.cpp in Sources */, FA0B7EAF1A95902C000E1D17 /* System.cpp in Sources */, FA0B7EE21A95902D000E1D17 /* Window.cpp in Sources */, @@ -4617,7 +4641,6 @@ FA0B7D9F1A95902C000E1D17 /* KTXHandler.cpp in Sources */, FA1E88831DF363DB00E808AA /* Filter.cpp in Sources */, FA0B7A2C1A958EA3000E1D17 /* b2CollideCircle.cpp in Sources */, - FA27B3A01B498151008A9DCE /* VideoStream.cpp in Sources */, FA0B7CEB1A95902C000E1D17 /* Event.cpp in Sources */, FA1557C31CE90BD200AFF582 /* EXRHandler.cpp in Sources */, FA27B3AA1B498151008A9DCE /* VideoStream.cpp in Sources */, @@ -4700,6 +4723,7 @@ FA0B7DCD1A95902C000E1D17 /* wrap_Keyboard.cpp in Sources */, FA0B7EE51A95902D000E1D17 /* Window.cpp in Sources */, FA6A2B6A1F5F7F560074C308 /* DataView.cpp in Sources */, + FA3C5E471F8D80CA0003C579 /* ShaderStage.cpp in Sources */, FA0B7E391A95902C000E1D17 /* World.cpp in Sources */, FA0B7ABD1A958EA3000E1D17 /* compress.c in Sources */, FA0B7ACB1A958EA3000E1D17 /* list.c in Sources */, @@ -4764,6 +4788,7 @@ FAF140881E20934C00F898D2 /* PoolAlloc.cpp in Sources */, FA0B7AAD1A958EA3000E1D17 /* b2WheelJoint.cpp in Sources */, FA0B7DEE1A95902C000E1D17 /* Mouse.cpp in Sources */, + FAA54ACC1F91660400A8FA7B /* TheoraVideoStream.cpp in Sources */, FA1E887E1DF363CD00E808AA /* Filter.cpp in Sources */, FA0B7D281A95902C000E1D17 /* wrap_GlyphData.cpp in Sources */, FA0B7DE21A95902C000E1D17 /* wrap_RandomGenerator.cpp in Sources */, @@ -4773,6 +4798,7 @@ FA0B7D0C1A95902C000E1D17 /* wrap_Filesystem.cpp in Sources */, FA0B7AD91A958EA3000E1D17 /* glad.cpp in Sources */, 217DFBF61D9F6D490055D849 /* options.c in Sources */, + FAA54ACD1F91660400A8FA7B /* OggDemuxer.cpp in Sources */, 217DFBD91D9F6D490055D849 /* auxiliar.c in Sources */, 217DFBDB1D9F6D490055D849 /* buffer.c in Sources */, FA0B7DB41A95902C000E1D17 /* wrap_ImageData.cpp in Sources */, diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 940f8f6ca..86059fcb9 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -22,6 +22,7 @@ #include "Graphics.h" #include "Buffer.h" #include "math/MathModule.h" +#include "data/DataModule.h" #include "Polyline.h" #include "font/Font.h" #include "window/Window.h" @@ -100,7 +101,7 @@ bool isDebugEnabled() love::Type Graphics::type("graphics", &Module::type); -Shader::ShaderSource Graphics::defaultShaderCode[Shader::STANDARD_MAX_ENUM][Shader::LANGUAGE_MAX_ENUM][2]; +Graphics::DefaultShaderCode Graphics::defaultShaderCode[Shader::STANDARD_MAX_ENUM][Shader::LANGUAGE_MAX_ENUM][2]; Graphics::Graphics() : width(0) @@ -115,6 +116,7 @@ Graphics::Graphics() , canvasSwitchCount(0) , drawCallsBatched(0) , capabilities() + , cachedShaderStages() { transformStack.reserve(16); transformStack.push_back(Matrix4()); @@ -149,6 +151,9 @@ Graphics::~Graphics() delete streamBufferState.vb[1]; delete streamBufferState.indexBuffer; + for (int i = 0; i < (int) ShaderStage::STAGE_MAX_ENUM; i++) + cachedShaderStages[i].clear(); + Shader::deinitialize(); } @@ -177,9 +182,77 @@ Video *Graphics::newVideo(love::video::VideoStream *stream, float dpiscale) return new Video(this, stream, dpiscale); } -bool Graphics::validateShader(bool gles, const Shader::ShaderSource &source, std::string &err) +ShaderStage *Graphics::newShaderStage(ShaderStage::StageType stage, const std::string &optsource) { - return Shader::validate(this, gles, source, true, err); + if (stage == ShaderStage::STAGE_MAX_ENUM) + throw love::Exception("Invalid shader stage."); + + const std::string &source = optsource.empty() ? getCurrentDefaultShaderCode().source[stage] : optsource; + + ShaderStage *s = nullptr; + std::string cachekey; + + if (!source.empty()) + { + data::HashFunction::Value hashvalue; + data::hash(data::HashFunction::FUNCTION_SHA1, source.c_str(), source.size(), hashvalue); + + cachekey = std::string(hashvalue.data, hashvalue.size); + + auto it = cachedShaderStages[stage].find(cachekey); + if (it != cachedShaderStages[stage].end()) + { + s = it->second; + s->retain(); + } + } + + if (s == nullptr) + { + s = newShaderStageInternal(stage, cachekey, source, getRenderer() == RENDERER_OPENGLES); + if (!cachekey.empty()) + cachedShaderStages[stage][cachekey] = s; + } + + return s; +} + +void Graphics::cleanupCachedShaderStage(ShaderStage::StageType type, const std::string &hashkey) +{ + cachedShaderStages[type].erase(hashkey); +} + +Shader *Graphics::newShader(const std::string &vertex, const std::string &pixel) +{ + if (vertex.empty() && pixel.empty()) + throw love::Exception("Error creating shader: no source code!"); + + StrongRef vertexstage(newShaderStage(ShaderStage::STAGE_VERTEX, vertex), Acquire::NORETAIN); + StrongRef pixelstage(newShaderStage(ShaderStage::STAGE_PIXEL, pixel), Acquire::NORETAIN); + + return newShaderInternal(vertexstage.get(), pixelstage.get()); +} + +bool Graphics::validateShader(bool gles, const std::string &vertex, const std::string &pixel, std::string &err) +{ + if (vertex.empty() && pixel.empty()) + { + err = "Error validating shader: no source code!"; + return false; + } + + StrongRef vertexstage; + StrongRef pixelstage; + + // Don't use cached shader stages, since the gles flag may not match the + // current renderer. + if (!vertex.empty()) + vertexstage.set(new ShaderStageForValidation(this, ShaderStage::STAGE_VERTEX, vertex, gles), Acquire::NORETAIN); + + if (!pixel.empty()) + pixelstage.set(new ShaderStageForValidation(this, ShaderStage::STAGE_PIXEL, pixel, gles), Acquire::NORETAIN); + + return Shader::validate(vertexstage.get(), pixelstage.get(), err); } int Graphics::getWidth() const @@ -1425,9 +1498,12 @@ Vector2 Graphics::inverseTransformPoint(Vector2 point) return p; } -const Shader::ShaderSource &Graphics::getCurrentDefaultShaderCode() const +const Graphics::DefaultShaderCode &Graphics::getCurrentDefaultShaderCode() const { - return defaultShaderCode[Shader::STANDARD_DEFAULT][getShaderLanguageTarget()][isGammaCorrect() ? 1 : 0]; + int languageindex = (int) getShaderLanguageTarget(); + int gammaindex = isGammaCorrect() ? 1 : 0; + + return defaultShaderCode[Shader::STANDARD_DEFAULT][languageindex][gammaindex]; } /** diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index b419ee73e..d9cd69bc4 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -34,6 +34,7 @@ #include "Texture.h" #include "Canvas.h" #include "Font.h" +#include "ShaderStage.h" #include "Shader.h" #include "Quad.h" #include "Mesh.h" @@ -44,6 +45,7 @@ #include "font/Rasterizer.h" #include "font/Font.h" #include "video/VideoStream.h" +#include "data/HashFunction.h" // C++ #include @@ -359,6 +361,11 @@ public: {} }; + struct DefaultShaderCode + { + std::string source[ShaderStage::STAGE_MAX_ENUM]; + }; + Graphics(); virtual ~Graphics(); @@ -378,7 +385,9 @@ public: virtual ParticleSystem *newParticleSystem(Texture *texture, int size) = 0; virtual Canvas *newCanvas(const Canvas::Settings &settings) = 0; - virtual Shader *newShader(const Shader::ShaderSource &source) = 0; + + ShaderStage *newShaderStage(ShaderStage::StageType stage, const std::string &source); + Shader *newShader(const std::string &vertex, const std::string &pixel); virtual Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) = 0; @@ -390,7 +399,7 @@ public: virtual Text *newText(Font *font, const std::vector &text = {}) = 0; - bool validateShader(bool gles, const Shader::ShaderSource &source, std::string &err); + bool validateShader(bool gles, const std::string &vertex, const std::string &pixel, std::string &err); /** * Resets the current color, background color, line style, and so forth. @@ -758,7 +767,9 @@ public: static void flushStreamDrawsGlobal(); virtual Shader::Language getShaderLanguageTarget() const = 0; - const Shader::ShaderSource &getCurrentDefaultShaderCode() const; + const DefaultShaderCode &getCurrentDefaultShaderCode() const; + + void cleanupCachedShaderStage(ShaderStage::StageType type, const std::string &cachekey); template T *getScratchBuffer(size_t count) @@ -806,7 +817,7 @@ public: static std::vector getConstants(StackType); // Default shader code (a shader is always required internally.) - static Shader::ShaderSource defaultShaderCode[Shader::STANDARD_MAX_ENUM][Shader::LANGUAGE_MAX_ENUM][2]; + static DefaultShaderCode defaultShaderCode[Shader::STANDARD_MAX_ENUM][Shader::LANGUAGE_MAX_ENUM][2]; protected: @@ -868,6 +879,8 @@ protected: } }; + virtual ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) = 0; + virtual Shader *newShaderInternal(ShaderStage *vertex, ShaderStage *pixel) = 0; virtual StreamBuffer *newStreamBuffer(BufferType type, size_t size) = 0; virtual void setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) = 0; @@ -926,6 +939,8 @@ private: std::vector scratchBuffer; + std::unordered_map cachedShaderStages[ShaderStage::STAGE_MAX_ENUM]; + static StringMap::Entry drawModeEntries[]; static StringMap drawModes; diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index dcd50d8e8..1c69d5568 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -29,103 +29,6 @@ // C++ #include -// TODO: Use love.graphics to determine actual limits? -static const TBuiltInResource defaultTBuiltInResource = { - /* .MaxLights = */ 32, - /* .MaxClipPlanes = */ 6, - /* .MaxTextureUnits = */ 32, - /* .MaxTextureCoords = */ 32, - /* .MaxVertexAttribs = */ 64, - /* .MaxVertexUniformComponents = */ 16384, - /* .MaxVaryingFloats = */ 128, - /* .MaxVertexTextureImageUnits = */ 32, - /* .MaxCombinedTextureImageUnits = */ 80, - /* .MaxTextureImageUnits = */ 32, - /* .MaxFragmentUniformComponents = */ 16384, - /* .MaxDrawBuffers = */ 8, - /* .MaxVertexUniformVectors = */ 4096, - /* .MaxVaryingVectors = */ 32, - /* .MaxFragmentUniformVectors = */ 4096, - /* .MaxVertexOutputVectors = */ 32, - /* .MaxFragmentInputVectors = */ 31, - /* .MinProgramTexelOffset = */ -8, - /* .MaxProgramTexelOffset = */ 7, - /* .MaxClipDistances = */ 8, - /* .MaxComputeWorkGroupCountX = */ 65535, - /* .MaxComputeWorkGroupCountY = */ 65535, - /* .MaxComputeWorkGroupCountZ = */ 65535, - /* .MaxComputeWorkGroupSizeX = */ 1024, - /* .MaxComputeWorkGroupSizeY = */ 1024, - /* .MaxComputeWorkGroupSizeZ = */ 64, - /* .MaxComputeUniformComponents = */ 1024, - /* .MaxComputeTextureImageUnits = */ 32, - /* .MaxComputeImageUniforms = */ 16, - /* .MaxComputeAtomicCounters = */ 4096, - /* .MaxComputeAtomicCounterBuffers = */ 8, - /* .MaxVaryingComponents = */ 128, - /* .MaxVertexOutputComponents = */ 128, - /* .MaxGeometryInputComponents = */ 128, - /* .MaxGeometryOutputComponents = */ 128, - /* .MaxFragmentInputComponents = */ 128, - /* .MaxImageUnits = */ 192, - /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144, - /* .MaxCombinedShaderOutputResources = */ 144, - /* .MaxImageSamples = */ 32, - /* .MaxVertexImageUniforms = */ 16, - /* .MaxTessControlImageUniforms = */ 16, - /* .MaxTessEvaluationImageUniforms = */ 16, - /* .MaxGeometryImageUniforms = */ 16, - /* .MaxFragmentImageUniforms = */ 16, - /* .MaxCombinedImageUniforms = */ 80, - /* .MaxGeometryTextureImageUnits = */ 16, - /* .MaxGeometryOutputVertices = */ 256, - /* .MaxGeometryTotalOutputComponents = */ 1024, - /* .MaxGeometryUniformComponents = */ 1024, - /* .MaxGeometryVaryingComponents = */ 64, - /* .MaxTessControlInputComponents = */ 128, - /* .MaxTessControlOutputComponents = */ 128, - /* .MaxTessControlTextureImageUnits = */ 16, - /* .MaxTessControlUniformComponents = */ 1024, - /* .MaxTessControlTotalOutputComponents = */ 4096, - /* .MaxTessEvaluationInputComponents = */ 128, - /* .MaxTessEvaluationOutputComponents = */ 128, - /* .MaxTessEvaluationTextureImageUnits = */ 16, - /* .MaxTessEvaluationUniformComponents = */ 1024, - /* .MaxTessPatchComponents = */ 120, - /* .MaxPatchVertices = */ 32, - /* .MaxTessGenLevel = */ 64, - /* .MaxViewports = */ 16, - /* .MaxVertexAtomicCounters = */ 4096, - /* .MaxTessControlAtomicCounters = */ 4096, - /* .MaxTessEvaluationAtomicCounters = */ 4096, - /* .MaxGeometryAtomicCounters = */ 4096, - /* .MaxFragmentAtomicCounters = */ 4096, - /* .MaxCombinedAtomicCounters = */ 4096, - /* .MaxAtomicCounterBindings = */ 8, - /* .MaxVertexAtomicCounterBuffers = */ 8, - /* .MaxTessControlAtomicCounterBuffers = */ 8, - /* .MaxTessEvaluationAtomicCounterBuffers = */ 8, - /* .MaxGeometryAtomicCounterBuffers = */ 8, - /* .MaxFragmentAtomicCounterBuffers = */ 8, - /* .MaxCombinedAtomicCounterBuffers = */ 8, - /* .MaxAtomicCounterBufferSize = */ 16384, - /* .MaxTransformFeedbackBuffers = */ 4, - /* .MaxTransformFeedbackInterleavedComponents = */ 64, - /* .MaxCullDistances = */ 8, - /* .MaxCombinedClipAndCullDistances = */ 8, - /* .MaxSamples = */ 32, - /* .limits = */ { - /* .nonInductiveForLoops = */ 1, - /* .whileLoops = */ 1, - /* .doWhileLoops = */ 1, - /* .generalUniformIndexing = */ 1, - /* .generalAttributeMatrixVectorIndexing = */ 1, - /* .generalVaryingIndexing = */ 1, - /* .generalSamplerIndexing = */ 1, - /* .generalVariableIndexing = */ 1, - /* .generalConstantMatrixVectorIndexing = */ 1, - }}; - namespace love { namespace graphics @@ -136,17 +39,15 @@ love::Type Shader::type("Shader", &Object::type); Shader *Shader::current = nullptr; Shader *Shader::standardShaders[Shader::STANDARD_MAX_ENUM] = {nullptr}; -Shader::Shader(const ShaderSource &source) - : shaderSource(source) +Shader::Shader(ShaderStage *vertex, ShaderStage *pixel) + : stages() { - auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx == nullptr) - throw love::Exception("love.graphics must be initialized to create a Shader."); - - bool gles = gfx->getRenderer() == Graphics::RENDERER_OPENGLES; std::string err; - if (!validate(gfx, gles, source, false, err)) + if (!validate(vertex, pixel, err)) throw love::Exception("%s", err.c_str()); + + stages[ShaderStage::STAGE_VERTEX] = vertex; + stages[ShaderStage::STAGE_PIXEL] = pixel; } Shader::~Shader() @@ -225,62 +126,15 @@ void Shader::checkMainTexture(Texture *tex) const checkMainTextureType(tex->getTextureType(), tex->getDepthSampleMode().hasValue); } -bool Shader::validate(Graphics *gfx, bool gles, const ShaderSource &source, bool checkWithDefaults, std::string &err) +bool Shader::validate(ShaderStage *vertex, ShaderStage *pixel, std::string &err) { - if (source.vertex.empty() && source.pixel.empty()) - { - err = "Error validating shader: no source code!"; - return false; - } - - bool supportsGLSL3 = gfx->getCapabilities().features[Graphics::FEATURE_GLSL3]; - - int defaultversion = gles ? 100 : 120; - EProfile defaultprofile = ENoProfile; - - glslang::TShader vshader(EShLangVertex); - glslang::TShader pshader(EShLangFragment); - - // TProgram must be destroyed before TShader. glslang::TProgram program; - auto addshader = [&](glslang::TShader &s, const std::string &src, ShaderStage stage) -> bool - { - if (src.empty()) - return true; + if (vertex != nullptr) + program.addShader(vertex->getGLSLangShader()); - const char *csrc = src.c_str(); - int srclen = (int) src.length(); - s.setStringsWithLengths(&csrc, &srclen, 1); - - bool forcedefault = false; - if (src.find("#define LOVE_GLSL1_ON_GLSL3") != std::string::npos) - forcedefault = true; - - bool forwardcompat = supportsGLSL3 && !forcedefault; - - if (!s.parse(&defaultTBuiltInResource, defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings)) - { - const char *stagename = "unknown"; - getConstant(stage, stagename); - err = "Error validating " + std::string(stagename) + " shader:\n\n" - + std::string(s.getInfoLog()) + "\n" + std::string(s.getInfoDebugLog()); - return false; - } - - program.addShader(&s); - return true; - }; - - const ShaderSource &defaults = gfx->getCurrentDefaultShaderCode(); - const std::string &vertcode = (checkWithDefaults && source.vertex.empty()) ? defaults.vertex : source.vertex; - const std::string &pixcode = (checkWithDefaults && source.pixel.empty()) ? defaults.pixel : source.pixel; - - if (!addshader(vshader, vertcode, STAGE_VERTEX)) - return false; - - if (!addshader(pshader, pixcode, STAGE_PIXEL)) - return false; + if (pixel != nullptr) + program.addShader(pixel->getGLSLangShader()); if (!program.link(EShMsgDefault)) { @@ -311,16 +165,6 @@ bool Shader::getConstant(Language in, const char *&out) return languages.find(in, out); } -bool Shader::getConstant(const char *in, ShaderStage &out) -{ - return stageNames.find(in, out); -} - -bool Shader::getConstant(ShaderStage in, const char *&out) -{ - return stageNames.find(in, out); -} - bool Shader::getConstant(const char *in, BuiltinUniform &out) { return builtinNames.find(in, out); @@ -341,14 +185,6 @@ StringMap::Entry Shader::languageEn StringMap Shader::languages(Shader::languageEntries, sizeof(Shader::languageEntries)); -StringMap::Entry Shader::stageNameEntries[] = -{ - { "vertex", STAGE_VERTEX }, - { "pixel", STAGE_PIXEL }, -}; - -StringMap Shader::stageNames(Shader::stageNameEntries, sizeof(Shader::stageNameEntries)); - StringMap::Entry Shader::builtinNameEntries[] = { { "MainTex", BUILTIN_TEXTURE_MAIN }, diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index aee4f8ff9..b338c6a4d 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -24,6 +24,7 @@ #include "common/Object.h" #include "common/StringMap.h" #include "Texture.h" +#include "ShaderStage.h" // STL #include @@ -59,13 +60,6 @@ public: LANGUAGE_MAX_ENUM }; - enum ShaderStage - { - STAGE_VERTEX, - STAGE_PIXEL, - STAGE_MAX_ENUM - }; - // Built-in uniform variables. enum BuiltinUniform { @@ -103,12 +97,6 @@ public: STANDARD_MAX_ENUM }; - struct ShaderSource - { - std::string vertex; - std::string pixel; - }; - struct MatrixSize { short columns; @@ -150,7 +138,7 @@ public: // Pointer to the default Shader. static Shader *standardShaders[STANDARD_MAX_ENUM]; - Shader(const ShaderSource &source); + Shader(ShaderStage *vertex, ShaderStage *pixel); virtual ~Shader(); /** @@ -197,7 +185,7 @@ public: virtual ptrdiff_t getHandle() const = 0; - static bool validate(Graphics *gfx, bool gles, const ShaderSource &source, bool checkWithDefaults, std::string &err); + static bool validate(ShaderStage *vertex, ShaderStage *pixel, std::string &err); static bool initialize(); static void deinitialize(); @@ -205,34 +193,17 @@ public: static bool getConstant(const char *in, Language &out); static bool getConstant(Language in, const char *&out); - static bool getConstant(const char *in, ShaderStage &out); - static bool getConstant(ShaderStage in, const char *&out); - static bool getConstant(const char *in, BuiltinUniform &out); static bool getConstant(BuiltinUniform in, const char *&out); protected: - struct CachedShaderStage - { - int referenceCount; - ShaderStage stage; - glslang::TShader *glslangShader; - ptrdiff_t handle; - }; - - // Source code used for this Shader. - ShaderSource shaderSource; - - static std::map cachedShaders; + StrongRef stages[ShaderStage::STAGE_MAX_ENUM]; private: static StringMap::Entry languageEntries[]; static StringMap languages; - - static StringMap::Entry stageNameEntries[]; - static StringMap stageNames; // Names for the built-in uniform variables. static StringMap::Entry builtinNameEntries[]; diff --git a/src/modules/graphics/ShaderStage.cpp b/src/modules/graphics/ShaderStage.cpp new file mode 100644 index 000000000..3dcd96a35 --- /dev/null +++ b/src/modules/graphics/ShaderStage.cpp @@ -0,0 +1,205 @@ +/** + * Copyright (c) 2006-2017 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "ShaderStage.h" +#include "common/Exception.h" +#include "Graphics.h" + +#include "libraries/glslang/glslang/Public/ShaderLang.h" + +// TODO: Use love.graphics to determine actual limits? +static const TBuiltInResource defaultTBuiltInResource = { + /* .MaxLights = */ 32, + /* .MaxClipPlanes = */ 6, + /* .MaxTextureUnits = */ 32, + /* .MaxTextureCoords = */ 32, + /* .MaxVertexAttribs = */ 64, + /* .MaxVertexUniformComponents = */ 16384, + /* .MaxVaryingFloats = */ 128, + /* .MaxVertexTextureImageUnits = */ 32, + /* .MaxCombinedTextureImageUnits = */ 80, + /* .MaxTextureImageUnits = */ 32, + /* .MaxFragmentUniformComponents = */ 16384, + /* .MaxDrawBuffers = */ 8, + /* .MaxVertexUniformVectors = */ 4096, + /* .MaxVaryingVectors = */ 32, + /* .MaxFragmentUniformVectors = */ 4096, + /* .MaxVertexOutputVectors = */ 32, + /* .MaxFragmentInputVectors = */ 31, + /* .MinProgramTexelOffset = */ -8, + /* .MaxProgramTexelOffset = */ 7, + /* .MaxClipDistances = */ 8, + /* .MaxComputeWorkGroupCountX = */ 65535, + /* .MaxComputeWorkGroupCountY = */ 65535, + /* .MaxComputeWorkGroupCountZ = */ 65535, + /* .MaxComputeWorkGroupSizeX = */ 1024, + /* .MaxComputeWorkGroupSizeY = */ 1024, + /* .MaxComputeWorkGroupSizeZ = */ 64, + /* .MaxComputeUniformComponents = */ 1024, + /* .MaxComputeTextureImageUnits = */ 32, + /* .MaxComputeImageUniforms = */ 16, + /* .MaxComputeAtomicCounters = */ 4096, + /* .MaxComputeAtomicCounterBuffers = */ 8, + /* .MaxVaryingComponents = */ 128, + /* .MaxVertexOutputComponents = */ 128, + /* .MaxGeometryInputComponents = */ 128, + /* .MaxGeometryOutputComponents = */ 128, + /* .MaxFragmentInputComponents = */ 128, + /* .MaxImageUnits = */ 192, + /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144, + /* .MaxCombinedShaderOutputResources = */ 144, + /* .MaxImageSamples = */ 32, + /* .MaxVertexImageUniforms = */ 16, + /* .MaxTessControlImageUniforms = */ 16, + /* .MaxTessEvaluationImageUniforms = */ 16, + /* .MaxGeometryImageUniforms = */ 16, + /* .MaxFragmentImageUniforms = */ 16, + /* .MaxCombinedImageUniforms = */ 80, + /* .MaxGeometryTextureImageUnits = */ 16, + /* .MaxGeometryOutputVertices = */ 256, + /* .MaxGeometryTotalOutputComponents = */ 1024, + /* .MaxGeometryUniformComponents = */ 1024, + /* .MaxGeometryVaryingComponents = */ 64, + /* .MaxTessControlInputComponents = */ 128, + /* .MaxTessControlOutputComponents = */ 128, + /* .MaxTessControlTextureImageUnits = */ 16, + /* .MaxTessControlUniformComponents = */ 1024, + /* .MaxTessControlTotalOutputComponents = */ 4096, + /* .MaxTessEvaluationInputComponents = */ 128, + /* .MaxTessEvaluationOutputComponents = */ 128, + /* .MaxTessEvaluationTextureImageUnits = */ 16, + /* .MaxTessEvaluationUniformComponents = */ 1024, + /* .MaxTessPatchComponents = */ 120, + /* .MaxPatchVertices = */ 32, + /* .MaxTessGenLevel = */ 64, + /* .MaxViewports = */ 16, + /* .MaxVertexAtomicCounters = */ 4096, + /* .MaxTessControlAtomicCounters = */ 4096, + /* .MaxTessEvaluationAtomicCounters = */ 4096, + /* .MaxGeometryAtomicCounters = */ 4096, + /* .MaxFragmentAtomicCounters = */ 4096, + /* .MaxCombinedAtomicCounters = */ 4096, + /* .MaxAtomicCounterBindings = */ 8, + /* .MaxVertexAtomicCounterBuffers = */ 8, + /* .MaxTessControlAtomicCounterBuffers = */ 8, + /* .MaxTessEvaluationAtomicCounterBuffers = */ 8, + /* .MaxGeometryAtomicCounterBuffers = */ 8, + /* .MaxFragmentAtomicCounterBuffers = */ 8, + /* .MaxCombinedAtomicCounterBuffers = */ 8, + /* .MaxAtomicCounterBufferSize = */ 16384, + /* .MaxTransformFeedbackBuffers = */ 4, + /* .MaxTransformFeedbackInterleavedComponents = */ 64, + /* .MaxCullDistances = */ 8, + /* .MaxCombinedClipAndCullDistances = */ 8, + /* .MaxSamples = */ 32, + /* .limits = */ { + /* .nonInductiveForLoops = */ 1, + /* .whileLoops = */ 1, + /* .doWhileLoops = */ 1, + /* .generalUniformIndexing = */ 1, + /* .generalAttributeMatrixVectorIndexing = */ 1, + /* .generalVaryingIndexing = */ 1, + /* .generalSamplerIndexing = */ 1, + /* .generalVariableIndexing = */ 1, + /* .generalConstantMatrixVectorIndexing = */ 1, + } +}; + +namespace love +{ +namespace graphics +{ + +ShaderStage::ShaderStage(Graphics *gfx, StageType stage, const std::string &glsl, bool gles, const std::string &cachekey) + : stageType(stage) + , source(glsl) + , cacheKey(cachekey) + , glslangShader(nullptr) +{ + EShLanguage glslangStage = EShLangCount; + if (stage == STAGE_VERTEX) + glslangStage = EShLangVertex; + else if (stage == STAGE_PIXEL) + glslangStage = EShLangFragment; + else + throw love::Exception("Cannot compile shader stage: unknown stage type."); + + glslangShader = new glslang::TShader(glslangStage); + + bool supportsGLSL3 = gfx->getCapabilities().features[Graphics::FEATURE_GLSL3]; + int defaultversion = gles ? 100 : 120; + EProfile defaultprofile = ENoProfile; + + const char *csrc = glsl.c_str(); + int srclen = (int) glsl.length(); + glslangShader->setStringsWithLengths(&csrc, &srclen, 1); + + bool forcedefault = false; + if (source.find("#define LOVE_GLSL1_ON_GLSL3") != std::string::npos) + forcedefault = true; + + bool forwardcompat = supportsGLSL3 && !forcedefault; + + if (!glslangShader->parse(&defaultTBuiltInResource, defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings)) + { + const char *stagename = "unknown"; + getConstant(stage, stagename); + + std::string err = "Error validating " + std::string(stagename) + " shader:\n\n" + + std::string(glslangShader->getInfoLog()) + "\n" + + std::string(glslangShader->getInfoDebugLog()); + + delete glslangShader; + throw love::Exception("%s", err.c_str()); + } +} + +ShaderStage::~ShaderStage() +{ + if (!cacheKey.empty()) + { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr) + gfx->cleanupCachedShaderStage(stageType, cacheKey); + } + + delete glslangShader; +} + +bool ShaderStage::getConstant(const char *in, StageType &out) +{ + return stageNames.find(in, out); +} + +bool ShaderStage::getConstant(StageType in, const char *&out) +{ + return stageNames.find(in, out); +} + +StringMap::Entry ShaderStage::stageNameEntries[] = +{ + { "vertex", STAGE_VERTEX }, + { "pixel", STAGE_PIXEL }, +}; + +StringMap ShaderStage::stageNames(ShaderStage::stageNameEntries, sizeof(ShaderStage::stageNameEntries)); + +} // graphics +} // love diff --git a/src/modules/graphics/ShaderStage.h b/src/modules/graphics/ShaderStage.h new file mode 100644 index 000000000..ff83b1001 --- /dev/null +++ b/src/modules/graphics/ShaderStage.h @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2006-2017 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#pragma once + +#include "common/Object.h" +#include "common/StringMap.h" +#include "Volatile.h" + +#include +#include + +namespace glslang +{ +class TShader; +} + +namespace love +{ +namespace graphics +{ + +class Graphics; + +class ShaderStage : public love::Object, public Volatile +{ +public: + + enum StageType + { + STAGE_VERTEX, + STAGE_PIXEL, + STAGE_MAX_ENUM + }; + + ShaderStage(Graphics *gfx, StageType stage, const std::string &glsl, bool gles, const std::string &cachekey); + virtual ~ShaderStage(); + + StageType getStageType() const { return stageType; } + const std::string &getSource() const { return source; } + const std::string &getWarnings() const { return warnings; } + glslang::TShader *getGLSLangShader() const { return glslangShader; } + + virtual ptrdiff_t getHandle() const = 0; + + static bool getConstant(const char *in, StageType &out); + static bool getConstant(StageType in, const char *&out); + +protected: + + std::string warnings; + +private: + + StageType stageType; + std::string source; + std::string cacheKey; + glslang::TShader *glslangShader; + + static StringMap::Entry stageNameEntries[]; + static StringMap stageNames; + +}; // ShaderStage + +class ShaderStageForValidation final : public ShaderStage +{ +public: + + ShaderStageForValidation(Graphics *gfx, StageType stage, const std::string &glsl, bool gles) + : ShaderStage(gfx, stage, glsl, gles, "") + {} + + virtual ~ShaderStageForValidation() {} + + ptrdiff_t getHandle() const override { return 0; } + bool loadVolatile() override { return true; } + void unloadVolatile() override { } + +}; // ShaderStageForValidation + +} // graphics +} // love diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 30bd76a36..328d0b2b2 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -52,14 +52,6 @@ enum TextureType TEXTURE_MAX_ENUM }; -class TextureTooLargeException : public love::Exception -{ -public: - TextureTooLargeException(const char *dimname, int pix) - : Exception("Cannot create texture: %s of %d pixels is too large for this system.", dimname, pix) - {} -}; - /** * Base class for 2D textures. All textures can be drawn with Quads, have a * width and height, and have filter and wrap modes. diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 2954d3b5b..3e8a248ad 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -30,6 +30,7 @@ #include "window/Window.h" #include "Buffer.h" #include "Text.h" +#include "ShaderStage.h" #include "libraries/xxHash/xxhash.h" @@ -126,9 +127,14 @@ love::graphics::Canvas *Graphics::newCanvas(const Canvas::Settings &settings) return new Canvas(settings); } -love::graphics::Shader *Graphics::newShader(const Shader::ShaderSource &source) +love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) { - return new Shader(source); + return new ShaderStage(this, stage, source, gles, cachekey); +} + +love::graphics::Shader *Graphics::newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel) +{ + return new Shader(vertex, pixel); } love::graphics::Buffer *Graphics::newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) @@ -281,7 +287,10 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b try { if (!Shader::standardShaders[i]) - Shader::standardShaders[i] = newShader(defaultShaderCode[i][target][gammacorrect]); + { + const auto &code = defaultShaderCode[i][target][gammacorrect]; + Shader::standardShaders[i] = love::graphics::Graphics::newShader(code.source[ShaderStage::STAGE_VERTEX], code.source[ShaderStage::STAGE_PIXEL]); + } } catch (love::Exception &) { diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 92efe3344..6b3655d89 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -68,7 +68,6 @@ public: love::graphics::ParticleSystem *newParticleSystem(Texture *texture, int size) override; love::graphics::Canvas *newCanvas(const Canvas::Settings &settings) override; - love::graphics::Shader *newShader(const Shader::ShaderSource &source) override; love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override; @@ -126,6 +125,8 @@ public: private: + love::graphics::ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) override; + love::graphics::Shader *newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel) override; love::graphics::StreamBuffer *newStreamBuffer(BufferType type, size_t size) override; void setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) override; void initCapabilities() override; diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 76b803633..6475e5120 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -36,8 +36,8 @@ namespace graphics namespace opengl { -Shader::Shader(const ShaderSource &source) - : love::graphics::Shader(source) +Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel) + : love::graphics::Shader(vertex, pixel) , program(0) , builtinUniforms() , builtinUniformInfo() @@ -73,71 +73,6 @@ Shader::~Shader() } } -GLuint Shader::compileCode(ShaderStage stage, const std::string &code) -{ - GLenum glstage; - const char *typestr; - - if (!getConstant(stage, typestr)) - typestr = ""; - - switch (stage) - { - case STAGE_VERTEX: - glstage = GL_VERTEX_SHADER; - break; - case STAGE_PIXEL: - glstage = GL_FRAGMENT_SHADER; - break; - default: - throw love::Exception("Cannot create shader object: unknown shader type."); - break; - } - - GLuint shaderid = glCreateShader(glstage); - - if (shaderid == 0) - { - if (glGetError() == GL_INVALID_ENUM) - throw love::Exception("Cannot create %s shader object: %s shaders not supported.", typestr, typestr); - else - throw love::Exception("Cannot create %s shader object.", typestr); - } - - const char *src = code.c_str(); - GLint srclen = (GLint) code.length(); - glShaderSource(shaderid, 1, (const GLchar **)&src, &srclen); - - glCompileShader(shaderid); - - GLint infologlen; - glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen); - - // Get any warnings the shader compiler may have produced. - if (infologlen > 0) - { - GLchar *infolog = new GLchar[infologlen]; - glGetShaderInfoLog(shaderid, infologlen, nullptr, infolog); - - // Save any warnings for later querying. - shaderWarnings[stage] = infolog; - - delete[] infolog; - } - - GLint status; - glGetShaderiv(shaderid, GL_COMPILE_STATUS, &status); - - if (status == GL_FALSE) - { - glDeleteShader(shaderid); - throw love::Exception("Cannot compile %s shader code:\n%s", - typestr, shaderWarnings[stage].c_str()); - } - - return shaderid; -} - void Shader::mapActiveUniforms() { // Built-in uniform locations default to -1 (nonexistent.) @@ -376,38 +311,22 @@ bool Shader::loadVolatile() textureUnits.clear(); textureUnits.push_back(TextureUnit()); - std::vector shaderids; - - auto gfx = Module::getInstance(Module::M_GRAPHICS); - const ShaderSource &defaults = gfx->getCurrentDefaultShaderCode(); - - // The shader program must have both vertex and pixel shader stages. - const std::string &vertexcode = shaderSource.vertex.empty() ? defaults.vertex : shaderSource.vertex; - const std::string &pixelcode = shaderSource.pixel.empty() ? defaults.pixel : shaderSource.pixel; - - try + for (const auto &stage : stages) { - shaderids.push_back(compileCode(STAGE_VERTEX, vertexcode)); - shaderids.push_back(compileCode(STAGE_PIXEL, pixelcode)); - } - catch (love::Exception &) - { - for (GLuint id : shaderids) - glDeleteShader(id); - throw; + if (stage.get() != nullptr) + stage->loadVolatile(); } program = glCreateProgram(); if (program == 0) - { - for (GLuint id : shaderids) - glDeleteShader(id); throw love::Exception("Cannot create shader program object."); - } - for (GLuint id : shaderids) - glAttachShader(program, id); + for (const auto &stage : stages) + { + if (stage.get() != nullptr) + glAttachShader(program, (GLuint) stage->getHandle()); + } // Bind generic vertex attribute indices to names in the shader. for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++) @@ -419,10 +338,6 @@ bool Shader::loadVolatile() glLinkProgram(program); - // Flag shaders for auto-deletion when the program object is deleted. - for (GLuint id : shaderids) - glDeleteShader(id); - GLint status; glGetProgramiv(program, GL_LINK_STATUS, &status); @@ -477,8 +392,6 @@ void Shader::unloadVolatile() // And the locations of any built-in uniform variables. for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++) builtinUniforms[i] = -1; - - shaderWarnings.clear(); } std::string Shader::getProgramWarnings() const @@ -506,11 +419,15 @@ std::string Shader::getWarnings() const std::string warnings; const char *stagestr; - // Get the individual shader stage warnings - for (const auto &warning : shaderWarnings) + for (const auto &stage : stages) { - if (getConstant(warning.first, stagestr)) - warnings += std::string(stagestr) + std::string(" shader:\n") + warning.second; + if (stage.get() == nullptr) + continue; + + const std::string &stagewarnings = stage->getWarnings(); + + if (ShaderStage::getConstant(stage->getStageType(), stagestr)) + warnings += std::string(stagestr) + std::string(" shader:\n") + stagewarnings; } warnings += getProgramWarnings(); diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index b2ac4950d..838422ad6 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -47,8 +47,7 @@ public: * Creates a new Shader using a list of source codes. * Source must contain either vertex or pixel shader code, or both. **/ - Shader(const ShaderSource &source); - + Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel); virtual ~Shader(); // Implements Volatile @@ -96,16 +95,11 @@ private: TextureType getUniformTextureType(GLenum type) const; bool isDepthTextureType(GLenum type) const; - GLuint compileCode(ShaderStage stage, const std::string &code); - void flushStreamDraws() const; // Get any warnings or errors generated only by the shader program object. std::string getProgramWarnings() const; - // Shader compiler warning strings for individual shader stages. - std::map shaderWarnings; - // volatile GLuint program; diff --git a/src/modules/graphics/opengl/ShaderStage.cpp b/src/modules/graphics/opengl/ShaderStage.cpp new file mode 100644 index 000000000..55ae5c2be --- /dev/null +++ b/src/modules/graphics/opengl/ShaderStage.cpp @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2006-2017 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "ShaderStage.h" + +namespace love +{ +namespace graphics +{ +namespace opengl +{ + +ShaderStage::ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey) + : love::graphics::ShaderStage(gfx, stage, source, gles, cachekey) + , glShader(0) +{ + loadVolatile(); +} + +ShaderStage::~ShaderStage() +{ + unloadVolatile(); +} + +bool ShaderStage::loadVolatile() +{ + if (glShader != 0) + return true; + + StageType stage = getStageType(); + const char *typestr = "unknown"; + getConstant(stage, typestr); + + GLenum glstage = 0; + if (stage == STAGE_VERTEX) + glstage = GL_VERTEX_SHADER; + else if (stage == STAGE_PIXEL) + glstage = GL_FRAGMENT_SHADER; + else + throw love::Exception("%s shader stage is not handled in OpenGL backend code.", typestr); + + glShader = glCreateShader(glstage); + + if (glShader == 0) + throw love::Exception("Cannot create OpenGL %s shader object.", typestr); + + const std::string &sourcestring = getSource(); + const char *src = sourcestring.c_str(); + GLint srclen = (GLint) sourcestring.length(); + + glShaderSource(glShader, 1, (const GLchar **)&src, &srclen); + glCompileShader(glShader); + + GLint infologlen; + glGetShaderiv(glShader, GL_INFO_LOG_LENGTH, &infologlen); + + if (infologlen > 0) + { + GLchar *infolog = new GLchar[infologlen]; + glGetShaderInfoLog(glShader, infologlen, nullptr, infolog); + + warnings = infolog; + delete[] infolog; + } + + GLint status = GL_FALSE; + glGetShaderiv(glShader, GL_COMPILE_STATUS, &status); + + if (glShader == GL_FALSE) + { + glDeleteShader(glShader); + throw love::Exception("Cannot compile %s shader code:\n%s", typestr, warnings.c_str()); + } + + return true; +} + +void ShaderStage::unloadVolatile() +{ + if (glShader != 0) + glDeleteShader(glShader); + + glShader = 0; +} + +} // opengl +} // graphics +} // love diff --git a/src/modules/graphics/opengl/ShaderStage.h b/src/modules/graphics/opengl/ShaderStage.h new file mode 100644 index 000000000..1add9dd0b --- /dev/null +++ b/src/modules/graphics/opengl/ShaderStage.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2006-2017 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#pragma once + +#include "graphics/ShaderStage.h" +#include "graphics/Volatile.h" +#include "OpenGL.h" + +namespace love +{ +namespace graphics +{ +namespace opengl +{ + +class ShaderStage final : public love::graphics::ShaderStage +{ +public: + + ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey); + virtual ~ShaderStage(); + + ptrdiff_t getHandle() const override { return glShader; } + + // Implements Volatile. + bool loadVolatile() override; + void unloadVolatile() override; + +private: + + GLuint glShader; + +}; // ShaderStage + +} // opengl +} // graphics +} // love diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index bbd6a4083..d4a51d237 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -1234,7 +1234,7 @@ int w_newCanvas(lua_State *L) return 1; } -static int w_getShaderSource(lua_State *L, int startidx, bool gles, Shader::ShaderSource &source) +static int w_getShaderSource(lua_State *L, int startidx, bool gles, std::string &vertexsource, std::string &pixelsource) { using namespace love::filesystem; @@ -1315,17 +1315,17 @@ static int w_getShaderSource(lua_State *L, int startidx, bool gles, Shader::Shad // vertex shader code if (lua_isstring(L, -2)) - source.vertex = luax_checkstring(L, -2); + vertexsource = luax_checkstring(L, -2); else if (has_arg1 && has_arg2) return luaL_error(L, "Could not parse vertex shader code (missing 'position' function?)"); // pixel shader code if (lua_isstring(L, -1)) - source.pixel = luax_checkstring(L, -1); + pixelsource = luax_checkstring(L, -1); else if (has_arg1 && has_arg2) return luaL_error(L, "Could not parse pixel shader code (missing 'effect' function?)"); - if (source.vertex.empty() && source.pixel.empty()) + if (vertexsource.empty() && pixelsource.empty()) { // Original args had source code, but effectCodeToGLSL couldn't translate it for (int i = startidx; i < startidx + 2; i++) @@ -1342,13 +1342,13 @@ int w_newShader(lua_State *L) { bool gles = instance()->getRenderer() == Graphics::RENDERER_OPENGLES; - Shader::ShaderSource source; - w_getShaderSource(L, 1, gles, source); + std::string vertexsource, pixelsource; + w_getShaderSource(L, 1, gles, vertexsource, pixelsource); bool should_error = false; try { - Shader *shader = instance()->newShader(source); + Shader *shader = instance()->newShader(vertexsource, pixelsource); luax_pushtype(L, shader); shader->release(); } @@ -1372,11 +1372,20 @@ int w_validateShader(lua_State *L) { bool gles = luax_checkboolean(L, 1); - Shader::ShaderSource source; - w_getShaderSource(L, 2, gles, source); + std::string vertexsource, pixelsource; + w_getShaderSource(L, 2, gles, vertexsource, pixelsource); + bool success = true; std::string err; - bool success = instance()->validateShader(gles, source, err); + try + { + success = instance()->validateShader(gles, vertexsource, pixelsource, err); + } + catch (love::Exception &e) + { + success = false; + err = e.what(); + } luax_pushboolean(L, success); @@ -2007,23 +2016,21 @@ int w_setDefaultShaderCode(lua_State *L) lua_getfield(L, -3, "videopixel"); lua_getfield(L, -4, "arraypixel"); - Shader::ShaderSource code; - code.vertex = luax_checkstring(L, -4); - code.pixel = luax_checkstring(L, -3); - - Shader::ShaderSource videocode; - videocode.vertex = luax_checkstring(L, -4); - videocode.pixel = luax_checkstring(L, -2); - - Shader::ShaderSource arraycode; - arraycode.vertex = luax_checkstring(L, -4); - arraycode.pixel = luax_checkstring(L, -1); + std::string vertex = luax_checkstring(L, -4); + std::string pixel = luax_checkstring(L, -3); + std::string videopixel = luax_checkstring(L, -2); + std::string arraypixel = luax_checkstring(L, -1); lua_pop(L, 5); - Graphics::defaultShaderCode[Shader::STANDARD_DEFAULT][lang][i] = code; - Graphics::defaultShaderCode[Shader::STANDARD_VIDEO][lang][i] = videocode; - Graphics::defaultShaderCode[Shader::STANDARD_ARRAY][lang][i] = arraycode; + Graphics::defaultShaderCode[Shader::STANDARD_DEFAULT][lang][i].source[ShaderStage::STAGE_VERTEX] = vertex; + Graphics::defaultShaderCode[Shader::STANDARD_DEFAULT][lang][i].source[ShaderStage::STAGE_PIXEL] = pixel; + + Graphics::defaultShaderCode[Shader::STANDARD_VIDEO][lang][i].source[ShaderStage::STAGE_VERTEX] = vertex; + Graphics::defaultShaderCode[Shader::STANDARD_VIDEO][lang][i].source[ShaderStage::STAGE_PIXEL] = videopixel; + + Graphics::defaultShaderCode[Shader::STANDARD_ARRAY][lang][i].source[ShaderStage::STAGE_VERTEX] = vertex; + Graphics::defaultShaderCode[Shader::STANDARD_ARRAY][lang][i].source[ShaderStage::STAGE_PIXEL] = arraypixel; } }