diff --git a/.gitignore b/.gitignore index a71a17a2c..760596757 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ gmon.out /*.sync /perf.data* +luac.out +*.patch diff --git a/Makefile b/Makefile index f91177d17..b541710c8 100644 --- a/Makefile +++ b/Makefile @@ -167,7 +167,7 @@ doc: cmake $(call COMPILE, codegen) $(call COMPILE, $@) -server client voxedit shapetool mapedit shadertool noisetool databasetool uitool tests tests-math tests-core tests-persistence tests-voxel benchmarks-voxel tests-noise tests-computeshadertool testmesh testcamera testdepthbuffer testnuklear testtexture testvoxelfont testplane testimgui testoctree testglslcomp testluaui testoctreevisit testshapebuilder tests-shadertool flatc computeshadertool: cmake +server client voxedit shapetool mapedit shadertool noisetool databasetool uitool tests tests-math tests-core tests-persistence tests-voxel benchmarks-voxel tests-noise tests-computeshadertool testmesh testcamera testdepthbuffer testnuklear testtexture testvoxelfont testplane testimgui testoctree testglslgeom testglslcomp testluaui testoctreevisit testshapebuilder tests-shadertool flatc computeshadertool: cmake $(call COMPILE, $@) $(call COMPILE, copy-data-shared) $(call COMPILE, copy-data-$@) diff --git a/TODO.md b/TODO.md index cb66806ad..984911247 100644 --- a/TODO.md +++ b/TODO.md @@ -14,10 +14,6 @@ INFO: (0) Validation output: shaders/world active samplers with a different type refer to the same texture image unit ``` -## Code generation - -Only replace the files if something has really changed. (`configure_file`?) - # Data handling The current approach with data dir must be extended/redone someone. There are way too many files installed per artifact atm. Also there should be CPack support to generate debian packages. diff --git a/cmake/macros.cmake b/cmake/macros.cmake index 65fcfc481..3cb9b11ee 100644 --- a/cmake/macros.cmake +++ b/cmake/macros.cmake @@ -48,115 +48,122 @@ endmacro() macro(generate_shaders TARGET) set(files ${ARGV}) list(REMOVE_AT files 0) - set(_headers) set(GEN_DIR ${GENERATE_DIR}/shaders/${TARGET}/) set(_template ${ROOT_DIR}/src/tools/shadertool/ShaderTemplate.h.in) set(_template_ub ${ROOT_DIR}/src/tools/shadertool/UniformBufferTemplate.h.in) file(MAKE_DIRECTORY ${GEN_DIR}) target_include_directories(${TARGET} PUBLIC ${GEN_DIR}) - foreach (shader_dir "${TARGET}" shared) - set(_dir ${ROOT_DIR}/${GAME_BASE_DIR}/${shader_dir}/shaders) - if (IS_DIRECTORY ${_dir}) - foreach (_file ${files}) - convert_to_camel_case(${_file} _f) - set(_shaderfile "${_f}Shader.h") - set(_shader "${GEN_DIR}${_shaderfile}") - if (EXISTS ${_dir}/${_file}.frag AND EXISTS ${_dir}/${_file}.vert) - add_custom_command( - OUTPUT ${_shader} - IMPLICIT_DEPENDS C ${_dir}/${_file}.frag C ${_dir}/${_file}.vert - COMMENT "Validate ${_file} and generate ${_shaderfile}" - COMMAND ${CMAKE_BINARY_DIR}/shadertool --glslang ${CMAKE_BINARY_DIR}/glslangValidator --shader ${_dir}/${_file} --shadertemplate ${_template} --buffertemplate ${_template_ub} --sourcedir ${GEN_DIR} - DEPENDS shadertool ${_dir}/${_file}.frag ${_dir}/${_file}.vert ${_template} ${_template_ub} - ) - list(APPEND _headers ${_shader}) - elseif (EXISTS ${_dir}/${_file}.comp) - add_custom_command( - OUTPUT ${_shader} - IMPLICIT_DEPENDS C ${_dir}/${_file}.comp - COMMENT "Validate ${_file} and generate ${_shaderfile}" - COMMAND ${CMAKE_BINARY_DIR}/shadertool --glslang ${CMAKE_BINARY_DIR}/glslangValidator --shader ${_dir}/${_file} --shadertemplate ${_template} --buffertemplate ${_template_ub} --sourcedir ${GEN_DIR} - DEPENDS shadertool ${_dir}/${_file}.comp ${_template} ${_template_ub} - ) - list(APPEND _headers ${_shader}) - endif() - endforeach() + set(_headers) + add_custom_target(UpdateShaders${TARGET}) + file(WRITE ${CMAKE_BINARY_DIR}/GenerateShaderHeader${TARGET}.cmake "configure_file(\${SRC} \${DST} @ONLY)") + foreach (_file ${files}) + set(_shaders) + set(_lastdir) + foreach (shader_dir "${TARGET}" shared) + set(_dir ${ROOT_DIR}/${GAME_BASE_DIR}/${shader_dir}/shaders) + if (EXISTS ${_dir}/${_file}.frag AND EXISTS ${_dir}/${_file}.vert) + list(APPEND _shaders ${_dir}/${_file}.frag ${_dir}/${_file}.vert) + set(_lastdir ${_dir}) + endif() + if (EXISTS ${_dir}/${_file}.geom) + list(APPEND _shaders ${_dir}/${_file}.geom) + set(_lastdir ${_dir}) + endif() + if (EXISTS ${_dir}/${_file}.comp) + list(APPEND _shaders ${_dir}/${_file}.comp) + set(_lastdir ${_dir}) + endif() + endforeach() + if (_shaders) + convert_to_camel_case(${_file} _f) + set(_shaderfile "${_f}Shader.h") + set(_shader "${GEN_DIR}${_shaderfile}") + add_custom_command( + OUTPUT ${_shader}.in + IMPLICIT_DEPENDS C ${_shaders} + COMMENT "Validate ${_file} and generate ${_shaderfile}" + COMMAND ${CMAKE_BINARY_DIR}/shadertool --glslang ${CMAKE_BINARY_DIR}/glslangValidator --postfix .in --shader ${_lastdir}/${_file} --shadertemplate ${_template} --buffertemplate ${_template_ub} --sourcedir ${GEN_DIR} + DEPENDS shadertool ${_shaders} ${_template} ${_template_ub} + ) + list(APPEND _headers ${_shader}) + add_custom_command(OUTPUT ${_shader} COMMAND ${CMAKE_COMMAND} -D SRC=${_shader}.in -D DST=${_shader} -P ${CMAKE_BINARY_DIR}/GenerateShaderHeader${TARGET}.cmake DEPENDS ${_shader}.in) + else() + message(FATAL_ERROR "Could not find any shader files for ${_file} and target '${TARGET}'") endif() endforeach() + convert_to_camel_case(${TARGET} _filetarget) - # TODO: not regenerated if files were added, renamed or removed set(_h ${GEN_DIR}/${_filetarget}Shaders.h) file(WRITE ${_h}.in "#pragma once\n") - foreach(header_path ${_headers}) + foreach (header_path ${_headers}) string(REPLACE "${GEN_DIR}" "" header "${header_path}") file(APPEND ${_h}.in "#include \"${header}\"\n") endforeach() - add_custom_command( - OUTPUT ${_h} - COMMAND ${CMAKE_COMMAND} - ARGS -E copy_if_different ${_h}.in ${_h} - COMMENT "Generate ${_h}" - ) add_custom_target(GenerateShaderBindings${TARGET} - DEPENDS ${_headers} ${_h} + DEPENDS ${_headers} COMMENT "Generate shader bindings for ${TARGET} in ${GEN_DIR}" ) - #target_sources(${TARGET} PUBLIC ${_headers} ${_h}) - set_source_files_properties(${_headers} ${_h} ${_h}.in PROPERTIES GENERATED TRUE) - add_dependencies(${TARGET} GenerateShaderBindings${TARGET}) - add_dependencies(codegen GenerateShaderBindings${TARGET}) + set_source_files_properties(${_headers} ${_h} PROPERTIES GENERATED TRUE) + add_custom_target(GenerateShaderHeader${TARGET} ${CMAKE_COMMAND} -D SRC=${_h}.in -D DST=${_h} -P ${CMAKE_BINARY_DIR}/GenerateShaderHeader${TARGET}.cmake) + add_dependencies(${TARGET} GenerateShaderHeader${TARGET} UpdateShaders${TARGET}) + add_dependencies(GenerateShaderHeader${TARGET} GenerateShaderBindings${TARGET}) + add_dependencies(codegen GenerateShaderHeader${TARGET} UpdateShaders${TARGET}) endmacro() macro(generate_compute_shaders TARGET) set(files ${ARGV}) list(REMOVE_AT files 0) - set(_headers) set(GEN_DIR ${GENERATE_DIR}/compute-shaders/${TARGET}/) set(_template ${ROOT_DIR}/src/tools/computeshadertool/ComputeShaderTemplate.h.in) file(MAKE_DIRECTORY ${GEN_DIR}) target_include_directories(${TARGET} PUBLIC ${GEN_DIR}) - foreach (shader_dir "${TARGET}" shared) - set(_dir ${ROOT_DIR}/${GAME_BASE_DIR}/${shader_dir}/shaders) - if (IS_DIRECTORY ${_dir}) - foreach (_file ${files}) - if (EXISTS ${_dir}/${_file}.cl) - convert_to_camel_case(${_file} _f) - set(_shaderfile "${_f}Shader.h") - set(_shader "${GEN_DIR}${_shaderfile}") - add_custom_command( - OUTPUT ${_shader} - IMPLICIT_DEPENDS C ${_dir}/${_file}.cl - COMMENT "Generate ${_shaderfile}" - COMMAND ${CMAKE_BINARY_DIR}/computeshadertool --shader ${_dir}/${_file} --shadertemplate ${_template} --sourcedir ${GEN_DIR} - DEPENDS computeshadertool ${_dir}/${_file}.cl ${_template} - ) - list(APPEND _headers ${_shader}) - endif() - endforeach() + set(_headers) + add_custom_target(UpdateComputeShaders${TARGET}) + file(WRITE ${CMAKE_BINARY_DIR}/GenerateComputeShaderHeader${TARGET}.cmake "configure_file(\${SRC} \${DST} @ONLY)") + foreach (_file ${files}) + set(_shaders) + set(_lastdir) + foreach (shader_dir "${TARGET}" shared) + set(_dir ${ROOT_DIR}/${GAME_BASE_DIR}/${shader_dir}/shaders) + if (EXISTS ${_dir}/${_file}.cl) + list(APPEND _shaders ${_dir}/${_file}.cl) + set(_lastdir ${_dir}) + endif() + endforeach() + if (_shaders) + convert_to_camel_case(${_file} _f) + set(_shaderfile "${_f}Shader.h") + set(_shader "${GEN_DIR}${_shaderfile}") + add_custom_command( + OUTPUT ${_shader}.in + IMPLICIT_DEPENDS C ${_shaders} + COMMENT "Validate ${_file} and generate ${_shaderfile}" + COMMAND ${CMAKE_BINARY_DIR}/computeshadertool --shader ${_dir}/${_file} --postfix .in --shadertemplate ${_template} --sourcedir ${GEN_DIR} + DEPENDS computeshadertool ${_shaders} ${_template} + ) + list(APPEND _headers ${_shader}) + add_custom_command(OUTPUT ${_shader} COMMAND ${CMAKE_COMMAND} -D SRC=${_shader}.in -D DST=${_shader} -P ${CMAKE_BINARY_DIR}/GenerateComputeShaderHeader${TARGET}.cmake DEPENDS ${_shader}.in) + else() + message(FATAL_ERROR "Could not find any shader files for ${_file} and target '${TARGET}'") endif() endforeach() + convert_to_camel_case(${TARGET} _filetarget) - # TODO: not regenerated if files were added, renamed or removed set(_h ${GEN_DIR}/${_filetarget}Shaders.h) file(WRITE ${_h}.in "#pragma once\n") - foreach(header_path ${_headers}) + foreach (header_path ${_headers}) string(REPLACE "${GEN_DIR}" "" header "${header_path}") file(APPEND ${_h}.in "#include \"${header}\"\n") endforeach() - add_custom_command( - OUTPUT ${_h} - COMMAND ${CMAKE_COMMAND} - ARGS -E copy_if_different ${_h}.in ${_h} - COMMENT "Generate ${_h}" - ) add_custom_target(GenerateComputeShaderBindings${TARGET} - DEPENDS ${_headers} ${_h} - COMMENT "Generate compute shader bindings for ${TARGET} in ${GEN_DIR}" + DEPENDS ${_headers} + COMMENT "Generate shader bindings for ${TARGET} in ${GEN_DIR}" ) - #target_sources(${TARGET} PUBLIC ${_headers} ${_h}) - set_source_files_properties(${_headers} ${_h} ${_h}.in PROPERTIES GENERATED TRUE) - add_dependencies(${TARGET} GenerateComputeShaderBindings${TARGET}) - add_dependencies(codegen GenerateComputeShaderBindings${TARGET}) + set_source_files_properties(${_headers} ${_h} PROPERTIES GENERATED TRUE) + add_custom_target(GenerateComputeShaderHeader${TARGET} ${CMAKE_COMMAND} -D SRC=${_h}.in -D DST=${_h} -P ${CMAKE_BINARY_DIR}/GenerateComputeShaderHeader${TARGET}.cmake) + add_dependencies(${TARGET} GenerateComputeShaderHeader${TARGET} UpdateComputeShaders${TARGET}) + add_dependencies(GenerateComputeShaderHeader${TARGET} GenerateComputeShaderBindings${TARGET}) + add_dependencies(codegen GenerateComputeShaderHeader${TARGET} UpdateComputeShaders${TARGET}) endmacro() macro(generate_db_models TARGET INPUT OUTPUT) diff --git a/data/testglslgeom/shaders/test.frag b/data/testglslgeom/shaders/test.frag new file mode 100644 index 000000000..8ed2f3fd5 --- /dev/null +++ b/data/testglslgeom/shaders/test.frag @@ -0,0 +1,6 @@ +$in vec3 v_color; +$out vec4 o_color; + +void main() { + o_color = vec4(v_color, 1.0); +} diff --git a/data/testglslgeom/shaders/test.geom b/data/testglslgeom/shaders/test.geom new file mode 100644 index 000000000..d50bce0cb --- /dev/null +++ b/data/testglslgeom/shaders/test.geom @@ -0,0 +1,26 @@ +layout(points) in; +layout(line_strip, max_vertices = 64) out; + +$in vec3 g_color[]; +$out vec3 v_color; + +uniform int u_sides; +uniform float u_radius; +uniform mat4 u_projection; + +const float PI = 3.1415926; + +void main() { + v_color = g_color[0]; + + float delta = PI * 2.0 / float(u_sides); + float ang = 0.0f; + for (int i = 0; i <= u_sides; i++) { + vec4 offset = vec4(cos(ang) * u_radius, -sin(ang) * u_radius, 0.0, 0.0); + gl_Position = u_projection * (gl_in[0].gl_Position + offset); + ang += delta; + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/data/testglslgeom/shaders/test.vert b/data/testglslgeom/shaders/test.vert new file mode 100644 index 000000000..879d7aab0 --- /dev/null +++ b/data/testglslgeom/shaders/test.vert @@ -0,0 +1,9 @@ +$in vec4 a_pos; +$in vec3 a_color; +uniform mat4 u_view; +$out vec3 g_color; + +void main() { + gl_Position = u_view * a_pos; + g_color = a_color; +} diff --git a/data/testglslgeom/testglslgeom-keybindings.cfg b/data/testglslgeom/testglslgeom-keybindings.cfg new file mode 100644 index 000000000..6734f66b3 --- /dev/null +++ b/data/testglslgeom/testglslgeom-keybindings.cfg @@ -0,0 +1,5 @@ +w +move_forward +a +move_left +s +move_backward +d +move_right +ctrl+q quit diff --git a/src/modules/render/TextureRenderer.cpp b/src/modules/render/TextureRenderer.cpp index 5d9948c08..e8eb7297f 100644 --- a/src/modules/render/TextureRenderer.cpp +++ b/src/modules/render/TextureRenderer.cpp @@ -38,10 +38,9 @@ void TextureRenderer::render(const glm::mat4& projection) { video::ScopedShader scoped(_textureShader); _textureShader.setProjection(projection); _textureShader.setTexture(video::TextureUnit::Zero); - _texturedFullscreenQuad.bind(); + video::ScopedVertexBuffer scopedBuf(_texturedFullscreenQuad); const int elements = _texturedFullscreenQuad.elements(0, _textureShader.getComponentsPos()); video::drawArrays(video::Primitive::Triangles, elements); - _texturedFullscreenQuad.unbind(); } void TextureRenderer::shutdown() { diff --git a/src/modules/testcore/TestApp.cpp b/src/modules/testcore/TestApp.cpp index 0598ed562..5876a78ef 100644 --- a/src/modules/testcore/TestApp.cpp +++ b/src/modules/testcore/TestApp.cpp @@ -115,6 +115,19 @@ void TestApp::onRenderUI() { if (ImGui::Checkbox("Toggle profiler", &temp)) { _renderTracing = toggleTrace(); } + if (ImGui::Checkbox("Render axis", &_renderAxis)) { + setRenderAxis(_renderAxis); + } + if (ImGui::Checkbox("Render plane", &_renderPlane)) { + setRenderPlane(_renderPlane); + } + if (ImGui::Checkbox("Camera motion", &_cameraMotion)) { + setCameraMotion(_cameraMotion); + } + if (ImGui::InputFloat("Camera speed", &_cameraSpeed, 0.02f, 0.1f)) { + setCameraSpeed(_cameraSpeed); + } + ImGui::InputVarFloat("Rotation speed", _rotationSpeed, 0.01f, 0.1f); ImGui::Separator(); if (ImGui::Button("Quit")) { requestQuit(); diff --git a/src/modules/testcore/TestMeshApp.cpp b/src/modules/testcore/TestMeshApp.cpp index c8405bec4..3cf9ea8dc 100644 --- a/src/modules/testcore/TestMeshApp.cpp +++ b/src/modules/testcore/TestMeshApp.cpp @@ -145,9 +145,6 @@ void TestMeshApp::onRenderUI() { ImGui::CheckboxVar("Show shadow cascades", _debugShadowCascade); static const char* items[] = { "Disable", "First", "Second", "Third", "Fourth" }; ImGui::Combo("Bone weight", &_boneInfluence, items, IM_ARRAYSIZE(items)); - if (ImGui::Checkbox("Render axis", &_renderAxis)) { - setRenderAxis(_renderAxis); - } ImGui::Checkbox("Render mesh", &_renderMesh); ImGui::Checkbox("Render normals", &_renderNormals); ImGui::Checkbox("Render bones", &_renderBones); @@ -158,15 +155,6 @@ void TestMeshApp::onRenderUI() { ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } - if (ImGui::Checkbox("Render plane", &_renderPlane)) { - setRenderPlane(_renderPlane); - } - if (ImGui::Checkbox("Camera motion", &_cameraMotion)) { - setCameraMotion(_cameraMotion); - } - if (ImGui::InputFloat("Camera speed", &_cameraSpeed, 0.02f, 0.1f)) { - setCameraSpeed(_cameraSpeed); - } if (ImGui::InputFloat3("Camera omega", glm::value_ptr(_omega))) { _camera.setOmega(_omega); } @@ -174,7 +162,6 @@ void TestMeshApp::onRenderUI() { ImGui::InputFloat("Shadow bias slope", &_shadowBiasSlope, 0.01f, 0.1f); ImGui::InputFloat("Shadow range", &_shadowRangeZ, 0.01f, 0.1f); ImGui::InputFloat("Fog range", &_fogRange, 0.01f, 0.1f); - ImGui::InputVarFloat("Rotation speed", _rotationSpeed, 0.01f, 0.1f); if (_mesh->animations() > 1 && ImGui::InputVarInt("Animation index", _animationIndex, 1, 1)) { _animationIndex->setVal(_mesh->currentAnimation()); } @@ -320,7 +307,7 @@ void TestMeshApp::doRender() { _shadowMapRenderShader.setNear(_camera.nearPlane()); // bind buffers - core_assert_always(_shadowMapDebugBuffer.bind()); + video::ScopedVertexBuffer scopedBuf(_shadowMapDebugBuffer); // configure shadow map texture video::bindTexture(video::TextureUnit::Zero, _depthBuffer); @@ -341,9 +328,6 @@ void TestMeshApp::doRender() { if (_depthBuffer.depthCompare()) { video::setupDepthCompareTexture(video::TextureUnit::Zero, _depthBuffer.textureType(), _depthBuffer.texture()); } - - // unbind buffer - _shadowMapDebugBuffer.unbind(); } if (!oldDepth) { diff --git a/src/modules/ui/imgui/IMGUIApp.cpp b/src/modules/ui/imgui/IMGUIApp.cpp index 3db244318..834eadbe3 100644 --- a/src/modules/ui/imgui/IMGUIApp.cpp +++ b/src/modules/ui/imgui/IMGUIApp.cpp @@ -342,7 +342,7 @@ core::AppState IMGUIApp::onRunning() { core_assert_always(_vbo.update(_bufferIndex, cmdList->VtxBuffer.Data, cmdList->VtxBuffer.Size * sizeof(ImDrawVert))); core_assert_always(_vbo.update(_indexBufferIndex, cmdList->IdxBuffer.Data, cmdList->IdxBuffer.Size * sizeof(ImDrawIdx))); - core_assert_always(_vbo.bind()); + video::ScopedVertexBuffer scopedBuf(_vbo); for (int i = 0; i < cmdList->CmdBuffer.Size; ++i) { const ImDrawCmd* cmd = &cmdList->CmdBuffer[i]; @@ -356,7 +356,6 @@ core::AppState IMGUIApp::onRunning() { } idxBufferOffset += cmd->ElemCount; } - _vbo.unbind(); } video::scissor(0, 0, renderTargetW, renderTargetH); diff --git a/src/modules/video/Mesh.cpp b/src/modules/video/Mesh.cpp index bc86a1df8..f1fe13ed5 100644 --- a/src/modules/video/Mesh.cpp +++ b/src/modules/video/Mesh.cpp @@ -592,7 +592,7 @@ int Mesh::render() { if (_state != io::IOSTATE_LOADED) { return 0; } - _vertexBuffer.bind(); + video::ScopedVertexBuffer scopedBuf(_vertexBuffer); int drawCalls = 0; for (const RenderMeshData& mesh : _meshData) { const uint32_t matIdx = mesh.materialIndex; @@ -602,8 +602,6 @@ int Mesh::render() { video::drawElementsBaseVertex(video::Primitive::Triangles, mesh.noOfIndices, mesh.baseIndex, mesh.baseVertex); ++drawCalls; } - _vertexBuffer.unbind(); - return drawCalls; } @@ -638,11 +636,10 @@ int Mesh::renderBones(video::Shader& shader) { boneData.reserve(_boneMapping.size() * 2); traverseBones(boneData, _scene->mRootNode, glm::mat4(1.0f), glm::vec3(0), false); _vertexBufferLines.update(_vertexBufferLinesIndex, boneData.data); - _vertexBufferLines.bind(); + video::ScopedVertexBuffer scopedBuf(_vertexBufferLines); ScopedLineWidth lineWidth(2.0f); const int elements = _vertexBufferLines.elements(_vertexBufferLinesIndex, 2); video::drawArrays(video::Primitive::Lines, elements); - _vertexBufferLines.unbind(); return 1; } @@ -681,11 +678,10 @@ int Mesh::renderNormals(video::Shader& shader) { } _vertexBufferLines.update(_vertexBufferLinesIndex, normalData.data); - _vertexBufferLines.bind(); + video::ScopedVertexBuffer scopedBuf(_vertexBufferLines); ScopedLineWidth lineWidth(2.0f); const int elements = _vertexBufferLines.elements(_vertexBufferLinesIndex, 2); video::drawArrays(video::Primitive::Lines, elements); - _vertexBufferLines.unbind(); return 1; } diff --git a/src/modules/video/Shader.cpp b/src/modules/video/Shader.cpp index 8134c022b..1f3f3e9be 100644 --- a/src/modules/video/Shader.cpp +++ b/src/modules/video/Shader.cpp @@ -17,12 +17,12 @@ namespace video { -#ifdef GL_ES_VERSION_2_0 +#ifdef GL_ES_VERSION_3_1 // default to opengles3 -int Shader::glslVersion = GLSLVersion::V300; +int Shader::glslVersion = GLSLVersion::V310; #else -// default to opengl3 -int Shader::glslVersion = GLSLVersion::V330; +// default to opengl4 +int Shader::glslVersion = GLSLVersion::V430; #endif Shader::Shader() { @@ -327,14 +327,12 @@ std::string Shader::getSource(ShaderType shaderType, const std::string& buffer, } std::string src; src.append("#version "); - if (shaderType == ShaderType::Compute) { - src.append("430"); - } else { - src.append(std::to_string(glslVersion)); - } + src.append(std::to_string(glslVersion)); src.append("\n"); - if (glslVersion < GLSLVersion::V140) { - //src.append("#extension GL_EXT_draw_instanced : enable\n"); + if (shaderType == ShaderType::Compute) { + src.append("#extension GL_ARB_compute_shader : enable\n"); + src.append("#extension GL_ARB_shader_storage_buffer_object : enable\n"); + src.append("#extension GL_ARB_compute_variable_group_size : enable\n"); } core::Var::visitSorted([&] (const core::VarPtr& var) { diff --git a/src/modules/video/ShaderManager.cpp b/src/modules/video/ShaderManager.cpp index c5a96d13e..634ede46d 100644 --- a/src/modules/video/ShaderManager.cpp +++ b/src/modules/video/ShaderManager.cpp @@ -1,3 +1,7 @@ +/** + * @file + */ + #include "ShaderManager.h" #include "core/Var.h" #include "core/Log.h" diff --git a/src/modules/video/ShaderManager.h b/src/modules/video/ShaderManager.h index 0052163a5..c9de9e343 100644 --- a/src/modules/video/ShaderManager.h +++ b/src/modules/video/ShaderManager.h @@ -9,6 +9,9 @@ namespace video { /** + * Register @c Shader instances here to let them automatically recompile + * on @c core::CV_SHADER @c core::CVar change. + * * @ingroup Video */ class ShaderManager { diff --git a/src/modules/video/Types.h b/src/modules/video/Types.h index 7ff747ff3..1df7de9a9 100644 --- a/src/modules/video/Types.h +++ b/src/modules/video/Types.h @@ -144,7 +144,11 @@ enum class VertexBufferMode { enum class Primitive { Points, Lines, + LinesAdjacency, Triangles, + TrianglesAdjacency, + LineStrip, + TriangleStrip, Max }; diff --git a/src/modules/video/VertexBuffer.h b/src/modules/video/VertexBuffer.h index 349f93519..80269894a 100644 --- a/src/modules/video/VertexBuffer.h +++ b/src/modules/video/VertexBuffer.h @@ -170,4 +170,18 @@ inline void VertexBuffer::setMode(int32_t idx, VertexBufferMode mode) { _modes[idx] = mode; } +class ScopedVertexBuffer { +private: + const VertexBuffer& _buf; +public: + ScopedVertexBuffer(const VertexBuffer& buf) : + _buf(buf) { + buf.bind(); + } + + ~ScopedVertexBuffer() { + _buf.unbind(); + } +}; + } diff --git a/src/modules/video/gl/GLMapping.h b/src/modules/video/gl/GLMapping.h index cff401529..478667310 100644 --- a/src/modules/video/gl/GLMapping.h +++ b/src/modules/video/gl/GLMapping.h @@ -157,7 +157,11 @@ static_assert(std::enum_value(Face::Max) == lengthof(Faces), "Array sizes don't static GLenum Primitives[] { GL_POINTS, GL_LINES, - GL_TRIANGLES + GL_LINES_ADJACENCY, + GL_TRIANGLES, + GL_TRIANGLES_ADJACENCY, + GL_LINE_STRIP, + GL_TRIANGLE_STRIP, }; static_assert(std::enum_value(Primitive::Max) == lengthof(Primitives), "Array sizes don't match Max"); diff --git a/src/modules/voxel/CMakeLists.txt b/src/modules/voxel/CMakeLists.txt index 29650bec2..d4f289b86 100644 --- a/src/modules/voxel/CMakeLists.txt +++ b/src/modules/voxel/CMakeLists.txt @@ -75,8 +75,6 @@ else() target_compile_options(${LIB} PRIVATE -O3) endif() -generate_compute_shaders(voxel meshextractor) - set(TEST_SRCS tests/AbstractVoxelTest.h tests/AbstractVoxFormatTest.h tests/AbstractVoxFormatTest.cpp diff --git a/src/modules/voxelrender/OctreeRenderer.cpp b/src/modules/voxelrender/OctreeRenderer.cpp index 2716670e5..2a5336ecf 100644 --- a/src/modules/voxelrender/OctreeRenderer.cpp +++ b/src/modules/voxelrender/OctreeRenderer.cpp @@ -115,9 +115,8 @@ void OctreeRenderer::renderOctreeNode(const video::Camera& camera, RenderOctreeN const int numIndices = renderNode->_vb.elements(renderNode->_indexBuffer, 1, sizeof(voxel::IndexType)); if (numIndices > 0 && renderNode->_renderThisNode) { if (camera.isVisible(renderNode->_aabb)) { - renderNode->_vb.bind(); + video::ScopedVertexBuffer scopedBuf(renderNode->_vb); video::drawElements(video::Primitive::Triangles, numIndices); - renderNode->_vb.unbind(); } } diff --git a/src/modules/voxelrender/RawVolumeRenderer.cpp b/src/modules/voxelrender/RawVolumeRenderer.cpp index 57013e3d5..0bfba6517 100644 --- a/src/modules/voxelrender/RawVolumeRenderer.cpp +++ b/src/modules/voxelrender/RawVolumeRenderer.cpp @@ -220,7 +220,7 @@ void RawVolumeRenderer::render(const video::Camera& camera) { if (nIndices == 0) { continue; } - core_assert_always(_vertexBuffer[idx].bind()); + video::ScopedVertexBuffer scopedBuf(_vertexBuffer[idx]); _shadowMapShader.setModel(glm::translate(_offsets[idx])); for (int i = 0; i < maxDepthBuffers; ++i) { _depthBuffer.bindTexture(i); @@ -228,7 +228,6 @@ void RawVolumeRenderer::render(const video::Camera& camera) { static_assert(sizeof(voxel::IndexType) == sizeof(uint32_t), "Index type doesn't match"); video::drawElements(video::Primitive::Triangles, nIndices); } - _vertexBuffer[idx].unbind(); } video::cullFace(video::Face::Back); if (oldBlend) { @@ -255,11 +254,10 @@ void RawVolumeRenderer::render(const video::Camera& camera) { if (nIndices == 0) { continue; } - core_assert_always(_vertexBuffer[idx].bind()); + video::ScopedVertexBuffer scopedBuf(_vertexBuffer[idx]); _worldShader.setModel(glm::translate(_offsets[idx])); static_assert(sizeof(voxel::IndexType) == sizeof(uint32_t), "Index type doesn't match"); video::drawElements(video::Primitive::Triangles, nIndices); - _vertexBuffer[idx].unbind(); } } _whiteTexture->unbind(); diff --git a/src/modules/voxelrender/WorldRenderer.cpp b/src/modules/voxelrender/WorldRenderer.cpp index bb492596d..41fa7449d 100644 --- a/src/modules/voxelrender/WorldRenderer.cpp +++ b/src/modules/voxelrender/WorldRenderer.cpp @@ -339,9 +339,8 @@ bool WorldRenderer::renderOpaqueBuffers() { if (numIndices == 0u) { return false; } - _opaqueBuffer.bind(); + video::ScopedVertexBuffer scopedBuf(_opaqueBuffer); video::drawElements(video::Primitive::Triangles, numIndices); - _opaqueBuffer.unbind(); return true; } @@ -350,9 +349,8 @@ bool WorldRenderer::renderWaterBuffers() { if (numIndices == 0u) { return false; } - _waterBuffer.bind(); + video::ScopedVertexBuffer scopedBuf(_waterBuffer); video::drawElements(video::Primitive::Triangles, numIndices); - _waterBuffer.unbind(); return true; } @@ -364,7 +362,7 @@ int WorldRenderer::renderPlants(const std::list& vbos, int* vertic continue; } - vbo->vb.bind(); + video::ScopedVertexBuffer scopedBuf(vbo->vb); if (vbo->amount == 1) { video::drawElements(video::Primitive::Triangles, numIndices); } else { @@ -557,7 +555,7 @@ int WorldRenderer::renderWorld(const video::Camera& camera, int* vertices) { _shadowMapRenderShader.setNear(camera.nearPlane()); // bind buffers - core_assert_always(_shadowMapDebugBuffer.bind()); + video::ScopedVertexBuffer scopedBuf(_shadowMapDebugBuffer); // configure shadow map texture video::bindTexture(video::TextureUnit::Zero, _depthBuffer); @@ -578,9 +576,6 @@ int WorldRenderer::renderWorld(const video::Camera& camera, int* vertices) { if (_depthBuffer.depthCompare()) { video::setupDepthCompareTexture(video::TextureUnit::Zero, _depthBuffer.textureType(), _depthBuffer.texture()); } - - // unbind buffer - _shadowMapDebugBuffer.unbind(); } if (_renderAABBs->boolVal()) { diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 7a6246567..de12b44bf 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(testmesh) add_subdirectory(testtexture) add_subdirectory(testplane) add_subdirectory(testglslcomp) +add_subdirectory(testglslgeom) add_subdirectory(testimgui) add_subdirectory(testnuklear) add_subdirectory(testluaui) diff --git a/src/tests/testdepthbuffer/TestDepthBuffer.cpp b/src/tests/testdepthbuffer/TestDepthBuffer.cpp index ab09df452..7064a228a 100644 --- a/src/tests/testdepthbuffer/TestDepthBuffer.cpp +++ b/src/tests/testdepthbuffer/TestDepthBuffer.cpp @@ -15,11 +15,10 @@ void TestDepthBuffer::doRender() { const int quadHeight = (int) (height / 3.0f); video::ScopedShader scopedShader(_shadowMapRenderShader); video::ScopedViewPort scopedViewport(width - quadWidth, 0, quadWidth, quadHeight); - core_assert_always(_texturedFullscreenQuad.bind()); + video::ScopedVertexBuffer scopedBuf(_texturedFullscreenQuad); video::bindTexture(video::TextureUnit::Zero, _depthBuffer); _shadowMapRenderShader.setShadowmap(video::TextureUnit::Zero); video::drawArrays(video::Primitive::Triangles, _texturedFullscreenQuad.elements(0)); - _texturedFullscreenQuad.unbind(); } core::AppState TestDepthBuffer::onInit() { diff --git a/src/tests/testglslgeom/CMakeLists.txt b/src/tests/testglslgeom/CMakeLists.txt new file mode 100644 index 000000000..2caa9f6a5 --- /dev/null +++ b/src/tests/testglslgeom/CMakeLists.txt @@ -0,0 +1,7 @@ +project(testglslgeom) +set(SRCS + TestGLSLGeom.h TestGLSLGeom.cpp +) +engine_add_executable(TARGET ${PROJECT_NAME} SRCS ${SRCS} WINDOWED NOINSTALL) +engine_target_link_libraries(TARGET ${PROJECT_NAME} DEPENDENCIES testcore imgui) +generate_shaders(${PROJECT_NAME} test) diff --git a/src/tests/testglslgeom/TestGLSLGeom.cpp b/src/tests/testglslgeom/TestGLSLGeom.cpp new file mode 100644 index 000000000..66537170a --- /dev/null +++ b/src/tests/testglslgeom/TestGLSLGeom.cpp @@ -0,0 +1,80 @@ +/** + * @file + */ +#include "TestGLSLGeom.h" +#include "io/Filesystem.h" +#include "core/Color.h" +#include "video/Camera.h" +#include "video/ScopedViewPort.h" + +TestGLSLGeom::TestGLSLGeom(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider) : + Super(metric, filesystem, eventBus, timeProvider) { + init(ORGANISATION, "testglslgeom"); +} + +core::AppState TestGLSLGeom::onInit() { + core::AppState state = Super::onInit(); + if (state != core::AppState::Running) { + return state; + } + + if (!_testShader.setup()) { + Log::error("Failed to init the compute shader"); + return core::AppState::InitFailure; + } + + _testShader.recordUsedUniforms(true); + + struct Buf { + glm::vec4 pos{0, 0, 0, 1}; + glm::vec3 color{1, 1, 1}; + }; + Buf buf; + int32_t bufIndex = _buffer.create(&buf, sizeof(buf)); + _buffer.setMode(bufIndex, video::VertexBufferMode::Static); + + video::Attribute attributePos; + attributePos.bufferIndex = bufIndex; + attributePos.index = _testShader.getLocationPos(); + attributePos.size = _testShader.getComponentsPos(); + attributePos.offset = offsetof(Buf, pos); + attributePos.stride = sizeof(Buf); + _buffer.addAttribute(attributePos); + + video::Attribute attributeColor; + attributeColor.bufferIndex = bufIndex; + attributeColor.index = _testShader.getLocationColor(); + attributeColor.size = _testShader.getComponentsColor(); + attributeColor.offset = offsetof(Buf, color); + attributeColor.stride = sizeof(Buf); + _buffer.addAttribute(attributeColor); + + video::clearColor(::core::Color::Black); + return state; +} + +core::AppState TestGLSLGeom::onCleanup() { + core::AppState state = Super::onCleanup(); + _testShader.shutdown(); + _buffer.shutdown(); + return state; +} + +void TestGLSLGeom::onRenderUI() { + ImGui::SliderFloat("radius", &_radius, 1.0f, 20.0f); + ImGui::SliderInt("sides", &_sides, 2, _testShader.getMaxGeometryVertices()); + Super::onRenderUI(); +} + +void TestGLSLGeom::doRender() { + video::ScopedShader scopedShd(_testShader); + _testShader.setSides(_sides); + _testShader.setRadius(_radius); + _testShader.setView(_camera.viewMatrix()); + _testShader.setProjection(_camera.projectionMatrix()); + video::ScopedVertexBuffer scopedBuf(_buffer); + const int elements = _buffer.elements(0, _testShader.getComponentsPos()); + video::drawArrays(_testShader.getPrimitiveTypeIn(), elements); +} + +TEST_APP(TestGLSLGeom) diff --git a/src/tests/testglslgeom/TestGLSLGeom.h b/src/tests/testglslgeom/TestGLSLGeom.h new file mode 100644 index 000000000..4aaadee80 --- /dev/null +++ b/src/tests/testglslgeom/TestGLSLGeom.h @@ -0,0 +1,31 @@ +/** + * @file + */ + +#pragma once + +#include "testcore/TestApp.h" +#include "video/VertexBuffer.h" +#include "TestglslgeomShaders.h" + +/** + * @brief Visual test for GLSL geometry shaders + * + * This test application is using a geometry shader to build a sphere from a single point. + */ +class TestGLSLGeom: public TestApp { +private: + using Super = TestApp; + shader::TestShader _testShader; + video::VertexBuffer _buffer; + int _sides = 16; + float _radius = 10.0f; + + void doRender() override; +public: + TestGLSLGeom(const metric::MetricPtr& metric, const io::FilesystemPtr& filesystem, const core::EventBusPtr& eventBus, const core::TimeProviderPtr& timeProvider); + + virtual void onRenderUI() override; + virtual core::AppState onInit() override; + virtual core::AppState onCleanup() override; +}; diff --git a/src/tests/testshapebuilder/TestShapeBuilder.cpp b/src/tests/testshapebuilder/TestShapeBuilder.cpp index 4dabf902b..b342ca0cd 100644 --- a/src/tests/testshapebuilder/TestShapeBuilder.cpp +++ b/src/tests/testshapebuilder/TestShapeBuilder.cpp @@ -171,9 +171,6 @@ void TestShapeBuilder::onRenderUI() { ImGui::Separator(); - ImGui::Checkbox("Render Axis", &_renderAxis); - ImGui::Checkbox("Render Plane", &_renderPlane); - if (ImGui::Button("Clear")) { for (int i = 0; i < _meshCount; ++i) { _shapeRenderer.deleteMesh(_meshes[i]); diff --git a/src/tools/computeshadertool/ComputeShaderTool.cpp b/src/tools/computeshadertool/ComputeShaderTool.cpp index b790a7224..1f7ec9204 100644 --- a/src/tools/computeshadertool/ComputeShaderTool.cpp +++ b/src/tools/computeshadertool/ComputeShaderTool.cpp @@ -41,6 +41,7 @@ core::AppState ComputeShaderTool::onRunning() { _shaderDirectory = getArgVal("--shaderdir"); _sourceDirectory = getArgVal("--sourcedir", _filesystem->basePath() + "src/modules/" + _namespaceSrc + "/"); + _postfix = getArgVal("--postfix", ""); if (!core::string::endsWith(_shaderDirectory, "/")) { _shaderDirectory = _shaderDirectory + "/"; @@ -68,7 +69,7 @@ core::AppState ComputeShaderTool::onRunning() { return core::AppState::Cleanup; } const std::string& templateShader = filesystem()->load(_shaderTemplateFile); - if (!computeshadertool::generateSrc(filesystem(), templateShader, _name, _namespaceSrc, _shaderDirectory, _sourceDirectory, _kernels, _structs)) { + if (!computeshadertool::generateSrc(filesystem(), templateShader, _name, _namespaceSrc, _shaderDirectory, _sourceDirectory, _kernels, _structs, _postfix)) { _exitCode = 100; return core::AppState::Cleanup; } diff --git a/src/tools/computeshadertool/ComputeShaderTool.h b/src/tools/computeshadertool/ComputeShaderTool.h index d7062588f..cef5fbac9 100644 --- a/src/tools/computeshadertool/ComputeShaderTool.h +++ b/src/tools/computeshadertool/ComputeShaderTool.h @@ -31,6 +31,7 @@ private: protected: std::string _namespaceSrc; std::string _sourceDirectory; + std::string _postfix; std::string _shaderDirectory; std::string _computeFilename; std::string _shaderTemplateFile; diff --git a/src/tools/computeshadertool/Generator.cpp b/src/tools/computeshadertool/Generator.cpp index eeaa5de9c..25cff5aaa 100644 --- a/src/tools/computeshadertool/Generator.cpp +++ b/src/tools/computeshadertool/Generator.cpp @@ -214,7 +214,8 @@ bool generateSrc(const io::FilesystemPtr& filesystem, const std::string& shaderDirectory, const std::string& sourceDirectory, const std::vector& _kernels, - const std::vector& _structs) { + const std::vector& _structs, + const std::string& postfix) { const std::string name = _name + "Shader"; std::vector shaderNameParts; @@ -267,7 +268,7 @@ bool generateSrc(const io::FilesystemPtr& filesystem, src = core::string::replaceAll(src, "$shutdown$", shutdown.str()); src = core::string::replaceAll(src, "$structs$", structs.str()); src = core::string::replaceAll(src, "$createkernels$", createKernels.str()); - const std::string targetFile = sourceDirectory + filename + ".h"; + const std::string targetFile = sourceDirectory + filename + ".h" + postfix; Log::info("Generate shader bindings for %s at %s", _name.c_str(), targetFile.c_str()); if (!filesystem->syswrite(targetFile, src)) { Log::error("Failed to write %s", targetFile.c_str()); diff --git a/src/tools/computeshadertool/Generator.h b/src/tools/computeshadertool/Generator.h index 8865df774..72c0fe9eb 100644 --- a/src/tools/computeshadertool/Generator.h +++ b/src/tools/computeshadertool/Generator.h @@ -18,6 +18,7 @@ extern bool generateSrc(const io::FilesystemPtr& filesystem, const std::string& sourceDirectory, const std::string& templateShader, const std::vector& kernels, - const std::vector& structs); + const std::vector& structs, + const std::string& postfix); } diff --git a/src/tools/shadertool/Generator.cpp b/src/tools/shadertool/Generator.cpp index 13f0d973c..cc6504a04 100644 --- a/src/tools/shadertool/Generator.cpp +++ b/src/tools/shadertool/Generator.cpp @@ -32,7 +32,7 @@ static const char *convertToTexUnit(int unit) { } bool generateSrc(const std::string& templateShader, const std::string& templateUniformBuffer, const ShaderStruct& shaderStruct, - const io::FilesystemPtr& filesystem, const std::string& namespaceSrc, const std::string& sourceDirectory, const std::string& shaderDirectory) { + const io::FilesystemPtr& filesystem, const std::string& namespaceSrc, const std::string& sourceDirectory, const std::string& shaderDirectory, const std::string& postfix) { std::string src(templateShader); const std::string& name = shaderStruct.name + "Shader"; @@ -93,15 +93,30 @@ bool generateSrc(const std::string& templateShader, const std::string& templateU attributes << "// no attributes"; } - std::stringstream setters; + std::stringstream methods; if (uniformSize > 0 || attributeSize > 0) { - setters << "\n"; + methods << "\n"; + } + if (shaderStruct.out.layout.maxGeometryVertices > 0) { + methods << "\tint getMaxGeometryVertices() const {\n"; + methods << "\t\treturn " << shaderStruct.out.layout.maxGeometryVertices << ";\n"; + methods << "\t}\n\n;"; + } + if (shaderStruct.out.layout.primitiveType != video::Primitive::Max) { + methods << "\tvideo::Primitive getPrimitiveTypeOut() const {\n"; + methods << "\t\treturn video::Primitive::" << util::getPrimitiveTypeString(shaderStruct.out.layout.primitiveType) << ";\n"; + methods << "\t}\n\n;"; + } + if (shaderStruct.in.layout.primitiveType != video::Primitive::Max) { + methods << "\tvideo::Primitive getPrimitiveTypeIn() const {\n"; + methods << "\t\treturn video::Primitive::" << util::getPrimitiveTypeString(shaderStruct.in.layout.primitiveType) << ";\n"; + methods << "\t}\n\n;"; } for (int i = 0; i < uniformSize; ++i) { const Variable& v = shaderStruct.uniforms[i]; const bool isInteger = v.isSingleInteger(); const std::string& uniformName = util::convertName(v.name, true); - setters << "\tinline bool set" << uniformName << "("; + methods << "\tinline bool set" << uniformName << "("; const Types& cType = util::resolveTypes(v.type); auto layoutIter = shaderStruct.layouts.find(v.name); Layout layout; @@ -110,126 +125,119 @@ bool generateSrc(const std::string& templateShader, const std::string& templateU } if (v.arraySize > 0 && isInteger) { - setters << "const "; + methods << "const "; } else if (cType.passBy == PassBy::Reference) { - setters << "const "; + methods << "const "; } - setters << cType.ctype; + methods << cType.ctype; if (v.arraySize == -1 || cType.passBy == PassBy::Pointer) { - setters << "*"; + methods << "*"; } else if (cType.passBy == PassBy::Reference) { if (v.arraySize <= 0) { - setters << "&"; + methods << "&"; } } else if (cType.passBy == PassBy::Value) { } if (v.arraySize > 0) { - setters << " (&" << v.name << ")[" << v.arraySize << "]"; + methods << " (&" << v.name << ")[" << v.arraySize << "]"; } else { - setters << " " << v.name; + methods << " " << v.name; } if (v.isSampler() && layout.binding != -1) { - setters << " = video::TextureUnit::" << convertToTexUnit(layout.binding); + methods << " = video::TextureUnit::" << convertToTexUnit(layout.binding); } if (v.arraySize == -1) { - setters << ", int amount"; + methods << ", int amount"; } - setters << ") const {\n"; + methods << ") const {\n"; - setters << "\t\tconst int location = "; + methods << "\t\tconst int location = "; if (layout.location != -1) { - setters << layout.location << ";\n"; + methods << layout.location << ";\n"; } else { - setters << "getUniformLocation(\"" << v.name << "\");\n"; - setters << "\t\tif (location == -1) {\n"; - setters << "\t\t\treturn false;\n"; - setters << "\t\t}\n"; + methods << "getUniformLocation(\"" << v.name << "\");\n"; + methods << "\t\tif (location == -1) {\n"; + methods << "\t\t\treturn false;\n"; + methods << "\t\t}\n"; } - setters << "\t\tsetUniform" << util::uniformSetterPostfix(v.type, v.arraySize == -1 ? 2 : v.arraySize); - setters << "(location, " << v.name; + methods << "\t\tsetUniform" << util::uniformSetterPostfix(v.type, v.arraySize == -1 ? 2 : v.arraySize); + methods << "(location, " << v.name; if (v.arraySize > 0) { - setters << ", " << v.arraySize; + methods << ", " << v.arraySize; } else if (v.arraySize == -1) { - setters << ", amount"; + methods << ", amount"; } - setters << ");\n"; - setters << "\t\treturn true;\n"; - setters << "\t}\n"; + methods << ");\n"; + methods << "\t\treturn true;\n"; + methods << "\t}\n"; if (v.isSampler()) { if (layout.binding != -1) { - setters << "\n\tinline video::TextureUnit getBound" << uniformName << "TexUnit() const {\n"; - setters << "\t\treturn video::TextureUnit::" << convertToTexUnit(layout.binding) << ";\n\t}\n"; + methods << "\n\tinline video::TextureUnit getBound" << uniformName << "TexUnit() const {\n"; + methods << "\t\treturn video::TextureUnit::" << convertToTexUnit(layout.binding) << ";\n\t}\n"; } } if (v.isSampler() || v.isImage()) { if (layout.imageFormat != video::ImageFormat::Max) { - setters << "\n\tinline video::ImageFormat getImageFormat" << uniformName << "() const {\n"; - setters << "\t\treturn video::ImageFormat::" << util::getImageFormatTypeString(layout.imageFormat) << ";\n\t}\n"; + methods << "\n\tinline video::ImageFormat getImageFormat" << uniformName << "() const {\n"; + methods << "\t\treturn video::ImageFormat::" << util::getImageFormatTypeString(layout.imageFormat) << ";\n\t}\n"; } - // TODO: generate texture with correct format and constraints. - } - if (layout.primitiveType != PrimitiveType::None) { - // TODO: - } - if (layout.blockLayout != BlockLayout::unknown) { - // TODO: } if (layout.localSize.x != -1) { - setters << "\n\tinline int getLocalSizeX() const {\n"; - setters << "\t\treturn " << layout.localSize.x << ";\n\t}\n"; + methods << "\n\tinline int getLocalSizeX() const {\n"; + methods << "\t\treturn " << layout.localSize.x << ";\n\t}\n"; } if (layout.localSize.y != -1) { - setters << "\n\tinline int getLocalSizeY() const {\n"; - setters << "\t\treturn " << layout.localSize.y << ";\n\t}\n"; + methods << "\n\tinline int getLocalSizeY() const {\n"; + methods << "\t\treturn " << layout.localSize.y << ";\n\t}\n"; } if (layout.localSize.z != -1) { - setters << "\n\tinline int getLocalSizeZ() const {\n"; - setters << "\t\treturn " << layout.localSize.z << ";\n\t}\n"; + methods << "\n\tinline int getLocalSizeZ() const {\n"; + methods << "\t\treturn " << layout.localSize.z << ";\n\t}\n"; } if (v.arraySize > 0) { - setters << "\n\tinline bool set" << uniformName << "(" << "const std::vector<" << cType.ctype << ">& var) const {\n"; - setters << "\t\tconst int location = getUniformLocation(\"" << v.name; - setters << "\");\n\t\tif (location == -1) {\n"; - setters << "\t\t\treturn false;\n"; - setters << "\t\t}\n"; - setters << "\t\tcore_assert((int)var.size() == " << v.arraySize << ");\n"; - setters << "\t\tsetUniform" << util::uniformSetterPostfix(v.type, v.arraySize) << "(location, &var.front(), var.size());\n"; - setters << "\t\treturn true;\n"; - setters << "\t}\n"; + methods << "\n\tinline bool set" << uniformName << "(" << "const std::vector<" << cType.ctype << ">& var) const {\n"; + methods << "\t\tconst int location = getUniformLocation(\"" << v.name; + methods << "\");\n\t\tif (location == -1) {\n"; + methods << "\t\t\treturn false;\n"; + methods << "\t\t}\n"; + methods << "\t\tcore_assert((int)var.size() == " << v.arraySize << ");\n"; + methods << "\t\tsetUniform" << util::uniformSetterPostfix(v.type, v.arraySize) << "(location, &var.front(), var.size());\n"; + methods << "\t\treturn true;\n"; + methods << "\t}\n"; } else if (cType.type == Variable::Type::VEC2 || cType.type == Variable::Type::VEC3 || cType.type == Variable::Type::VEC4) { - setters << "\n\tinline bool set" << uniformName << "(" << "const std::vector& var) const {\n"; - setters << "\t\tconst int location = getUniformLocation(\"" << v.name; - setters << "\");\n\t\tif (location == -1) {\n"; - setters << "\t\t\treturn false;\n"; - setters << "\t\t}\n"; - setters << "\t\tcore_assert(int(var.size()) % " << cType.components << " == 0);\n"; - setters << "\t\tsetUniformfv(location, &var.front(), " << cType.components << ", " << cType.components << ");\n"; - setters << "\t\treturn true;\n"; - setters << "\t}\n"; + methods << "\n\tinline bool set" << uniformName << "(" << "const std::vector& var) const {\n"; + methods << "\t\tconst int location = getUniformLocation(\"" << v.name; + methods << "\");\n\t\tif (location == -1) {\n"; + methods << "\t\t\treturn false;\n"; + methods << "\t\t}\n"; + methods << "\t\tcore_assert(int(var.size()) % " << cType.components << " == 0);\n"; + methods << "\t\tsetUniformfv(location, &var.front(), " << cType.components << ", " << cType.components << ");\n"; + methods << "\t\treturn true;\n"; + methods << "\t}\n"; } if (i < uniformSize- - 2) { - setters << "\n"; + methods << "\n"; } #if 0 if (v.arraySize == -1 || v.arraySize > 1) { - setters << "\tinline bool set" << uniformName << "("; + methods << "\tinline bool set" << uniformName << "("; const Types& cType = util::getTypes(v.type); - setters << "const std::vector<" << cType.ctype << ">& " << v.name << ") const {\n"; - setters << "\t\tif (!hasUniform(\"" << v.name << "[0]\")) {\n"; - setters << "\t\t\treturn false;\n"; - setters << "\t\t}\n"; - setters << "\t\tsetUniform" << util::uniformSetterPostfix(v.type, v.arraySize == -1 ? 2 : v.arraySize); - setters << "(\"" << v.name << "[0]\", &" << v.name << "[0], " << v.name << ".size());\n"; - setters << "\t\treturn true;\n"; - setters << "\t}\n"; + methods << "const std::vector<" << cType.ctype << ">& " << v.name << ") const {\n"; + methods << "\t\tif (!hasUniform(\"" << v.name << "[0]\")) {\n"; + methods << "\t\t\treturn false;\n"; + methods << "\t\t}\n"; + methods << "\t\tsetUniform" << util::uniformSetterPostfix(v.type, v.arraySize == -1 ? 2 : v.arraySize); + methods << "(\"" << v.name << "[0]\", &" << v.name << "[0], " << v.name << ".size());\n"; + methods << "\t\treturn true;\n"; + methods << "\t}\n"; if (i < uniformSize- - 2) { - setters << "\n"; + methods << "\n"; } } #endif @@ -238,70 +246,70 @@ bool generateSrc(const std::string& templateShader, const std::string& templateU const Variable& v = shaderStruct.attributes[i]; const std::string& attributeName = util::convertName(v.name, true); const bool isInt = v.isInteger(); - setters << "\tinline bool init" << attributeName << "Custom(size_t stride = "; - setters << "sizeof(" << util::resolveTypes(v.type).ctype << ")"; - setters << ", const void* pointer = nullptr, video::DataType type = "; + methods << "\tinline bool init" << attributeName << "Custom(size_t stride = "; + methods << "sizeof(" << util::resolveTypes(v.type).ctype << ")"; + methods << ", const void* pointer = nullptr, video::DataType type = "; if (isInt) { - setters << "video::DataType::Int"; + methods << "video::DataType::Int"; } else { - setters << "video::DataType::Float"; + methods << "video::DataType::Float"; } - setters << ", int size = "; - setters << util::resolveTypes(v.type).components << ", "; - setters << "bool isInt = "; - setters << (isInt ? "true" : "false"); - setters << ", bool normalize = false) const {\n"; - setters << "\t\tconst int loc = enableVertexAttributeArray(\"" << v.name << "\");\n"; - setters << "\t\tif (loc == -1) {\n"; - setters << "\t\t\treturn false;\n"; - setters << "\t\t}\n"; - setters << "\t\tif (isInt) {\n"; - setters << "\t\t\tsetVertexAttributeInt(loc, size, type, stride, pointer);\n"; - setters << "\t\t} else {\n"; - setters << "\t\t\tsetVertexAttribute(loc, size, type, normalize, stride, pointer);\n"; - setters << "\t\t}\n"; - setters << "\t\treturn true;\n"; - setters << "\t}\n\n"; - setters << "\tinline int getLocation" << attributeName << "() const {\n"; - setters << "\t\treturn getAttributeLocation(\"" << v.name << "\");\n"; - setters << "\t}\n\n"; - setters << "\tinline int getComponents" << attributeName << "() const {\n"; - setters << "\t\treturn getAttributeComponents(\"" << v.name << "\");\n"; - setters << "\t}\n\n"; - setters << "\tinline bool init" << attributeName << "() const {\n"; - setters << "\t\tconst int loc = enableVertexAttributeArray(\"" << v.name << "\");\n"; - setters << "\t\tif (loc == -1) {\n"; - setters << "\t\t\treturn false;\n"; - setters << "\t\t}\n"; - setters << "\t\tconst size_t stride = sizeof(" << util::resolveTypes(v.type).ctype << ");\n"; - setters << "\t\tconst void* pointer = nullptr;\n"; - setters << "\t\tconst video::DataType type = "; + methods << ", int size = "; + methods << util::resolveTypes(v.type).components << ", "; + methods << "bool isInt = "; + methods << (isInt ? "true" : "false"); + methods << ", bool normalize = false) const {\n"; + methods << "\t\tconst int loc = enableVertexAttributeArray(\"" << v.name << "\");\n"; + methods << "\t\tif (loc == -1) {\n"; + methods << "\t\t\treturn false;\n"; + methods << "\t\t}\n"; + methods << "\t\tif (isInt) {\n"; + methods << "\t\t\tsetVertexAttributeInt(loc, size, type, stride, pointer);\n"; + methods << "\t\t} else {\n"; + methods << "\t\t\tsetVertexAttribute(loc, size, type, normalize, stride, pointer);\n"; + methods << "\t\t}\n"; + methods << "\t\treturn true;\n"; + methods << "\t}\n\n"; + methods << "\tinline int getLocation" << attributeName << "() const {\n"; + methods << "\t\treturn getAttributeLocation(\"" << v.name << "\");\n"; + methods << "\t}\n\n"; + methods << "\tinline int getComponents" << attributeName << "() const {\n"; + methods << "\t\treturn getAttributeComponents(\"" << v.name << "\");\n"; + methods << "\t}\n\n"; + methods << "\tinline bool init" << attributeName << "() const {\n"; + methods << "\t\tconst int loc = enableVertexAttributeArray(\"" << v.name << "\");\n"; + methods << "\t\tif (loc == -1) {\n"; + methods << "\t\t\treturn false;\n"; + methods << "\t\t}\n"; + methods << "\t\tconst size_t stride = sizeof(" << util::resolveTypes(v.type).ctype << ");\n"; + methods << "\t\tconst void* pointer = nullptr;\n"; + methods << "\t\tconst video::DataType type = "; if (isInt) { - setters << "video::DataType::Int"; + methods << "video::DataType::Int"; } else { - setters << "video::DataType::Float"; + methods << "video::DataType::Float"; } - setters << ";\n"; - setters << "\t\tconst int size = getAttributeComponents(loc);\n"; + methods << ";\n"; + methods << "\t\tconst int size = getAttributeComponents(loc);\n"; if (isInt) { - setters << "\t\tsetVertexAttributeInt(loc, size, type, stride, pointer);\n"; + methods << "\t\tsetVertexAttributeInt(loc, size, type, stride, pointer);\n"; } else { - setters << "\t\tsetVertexAttribute(loc, size, type, false, stride, pointer);\n"; + methods << "\t\tsetVertexAttribute(loc, size, type, false, stride, pointer);\n"; } - setters << "\t\treturn true;\n"; - setters << "\t}\n\n"; - setters << "\tinline bool set" << attributeName << "Divisor(uint32_t divisor) const {\n"; - setters << "\t\tconst int location = getAttributeLocation(\"" << v.name << "\");\n"; - setters << "\t\treturn setDivisor(location, divisor);\n"; - setters << "\t}\n"; + methods << "\t\treturn true;\n"; + methods << "\t}\n\n"; + methods << "\tinline bool set" << attributeName << "Divisor(uint32_t divisor) const {\n"; + methods << "\t\tconst int location = getAttributeLocation(\"" << v.name << "\");\n"; + methods << "\t\treturn setDivisor(location, divisor);\n"; + methods << "\t}\n"; if (i < attributeSize - 1) { - setters << "\n"; + methods << "\n"; } } if (!shaderStruct.uniformBlocks.empty()) { - setters << "\n"; + methods << "\n"; } std::stringstream ub; std::stringstream shutdown; @@ -354,17 +362,17 @@ bool generateSrc(const std::string& templateShader, const std::string& templateU ub << "\n\tinline operator const video::UniformBuffer&() const {\n"; ub << "\t\treturn _" << uniformBufferName << ";\n"; ub << "\t}\n"; - setters << "\t/**\n"; - setters << "\t * @brief The the uniform buffer for the uniform block " << ubuf.name << "\n"; - setters << "\t */\n"; - setters << "\tinline bool set" << uniformBufferStructName << "(const video::UniformBuffer& buf) {\n"; - setters << "\t\treturn setUniformBuffer(\"" << ubuf.name << "\", buf);\n"; - setters << "\t}\n"; + methods << "\t/**\n"; + methods << "\t * @brief The the uniform buffer for the uniform block " << ubuf.name << "\n"; + methods << "\t */\n"; + methods << "\tinline bool set" << uniformBufferStructName << "(const video::UniformBuffer& buf) {\n"; + methods << "\t\treturn setUniformBuffer(\"" << ubuf.name << "\", buf);\n"; + methods << "\t}\n"; std::string generatedUb = core::string::replaceAll(templateUniformBuffer, "$name$", uniformBufferStructName); generatedUb = core::string::replaceAll(generatedUb, "$namespace$", namespaceSrc); generatedUb = core::string::replaceAll(generatedUb, "$uniformbuffers$", ub.str()); - generatedUb = core::string::replaceAll(generatedUb, "$setters$", ""); + generatedUb = core::string::replaceAll(generatedUb, "$methods$", ""); generatedUb = core::string::replaceAll(generatedUb, "$shutdown$", shutdown.str()); const std::string targetFileUb = sourceDirectory + uniformBufferStructName + ".h"; @@ -379,10 +387,10 @@ bool generateSrc(const std::string& templateShader, const std::string& templateU } src = core::string::replaceAll(src, "$attributes$", attributes.str()); - src = core::string::replaceAll(src, "$setters$", setters.str()); + src = core::string::replaceAll(src, "$methods$", methods.str()); src = core::string::replaceAll(src, "$includes$", includes.str()); - const std::string targetFile = sourceDirectory + filename + ".h"; + const std::string targetFile = sourceDirectory + filename + ".h" + postfix; Log::debug("Generate shader bindings for %s at %s", shaderStruct.name.c_str(), targetFile.c_str()); if (!filesystem->syswrite(targetFile, src)) { Log::error("Failed to write %s", targetFile.c_str()); diff --git a/src/tools/shadertool/Generator.h b/src/tools/shadertool/Generator.h index cf4041cad..b6922de08 100644 --- a/src/tools/shadertool/Generator.h +++ b/src/tools/shadertool/Generator.h @@ -11,6 +11,6 @@ namespace shadertool { extern bool generateSrc(const std::string& templateShader, const std::string& templateUniformBuffer, const ShaderStruct& shaderStruct, - const io::FilesystemPtr& filesystem, const std::string& namespaceSrc, const std::string& sourceDirectory, const std::string& shaderDirectory); + const io::FilesystemPtr& filesystem, const std::string& namespaceSrc, const std::string& sourceDirectory, const std::string& shaderDirectory, const std::string& postfix); } diff --git a/src/tools/shadertool/Parser.cpp b/src/tools/shadertool/Parser.cpp index 598db62ec..0aa727e94 100644 --- a/src/tools/shadertool/Parser.cpp +++ b/src/tools/shadertool/Parser.cpp @@ -17,8 +17,7 @@ namespace shadertool { -static const char* PrimitiveTypeStr[] { - nullptr, +static const char* PrimitiveStr[] { "points", "lines", "lines_adjacency", @@ -27,18 +26,15 @@ static const char* PrimitiveTypeStr[] { "line_strip", "triangle_strip" }; -static_assert(lengthof(PrimitiveTypeStr) == std::enum_value(PrimitiveType::Max), "PrimitiveTypeStr doesn't match enum"); +static_assert(lengthof(PrimitiveStr) == std::enum_value(video::Primitive::Max), "PrimitiveStr doesn't match enum"); -static PrimitiveType layoutPrimitiveType(const std::string& token) { - for (int i = 0; i < lengthof(PrimitiveTypeStr); ++i) { - if (PrimitiveTypeStr[i] == nullptr) { - continue; - } - if (token == PrimitiveTypeStr[i]) { - return (PrimitiveType)i; +static video::Primitive layoutPrimitiveType(const std::string& token) { + for (int i = 0; i < lengthof(PrimitiveStr); ++i) { + if (token == PrimitiveStr[i]) { + return (video::Primitive)i; } } - return PrimitiveType::None; + return video::Primitive::Max; } bool parseLayout(TokenIterator& tok, Layout& layout) { @@ -156,7 +152,12 @@ bool parseLayout(TokenIterator& tok, Layout& layout) { if (format != video::ImageFormat::Max) { layout.imageFormat = format; } else { - Log::warn("Unknown token given for layout: %s (line %i)", token.c_str(), tok.line()); + video::Primitive primitiveType = layoutPrimitiveType(token); + if (primitiveType != video::Primitive::Max) { + layout.primitiveType = primitiveType; + } else { + Log::warn("Unknown token given for layout: %s (line %i)", token.c_str(), tok.line()); + } } } } while (token != ")"); @@ -216,6 +217,10 @@ bool parse(ShaderStruct& shaderStruct, const std::string& shaderFile, const std: Log::warn("SSBO not supported"); } else if (token == "uniform") { v = &shaderStruct.uniforms; + } else if (hasLayout && token == "in") { + shaderStruct.in.layout = layout; + } else if (hasLayout && token == "out") { + shaderStruct.out.layout = layout; } else if (uniformBlock) { if (token == "}") { uniformBlock = false; diff --git a/src/tools/shadertool/ShaderTemplate.h.in b/src/tools/shadertool/ShaderTemplate.h.in index 1b3cb8816..7f8270383 100644 --- a/src/tools/shadertool/ShaderTemplate.h.in +++ b/src/tools/shadertool/ShaderTemplate.h.in @@ -62,7 +62,7 @@ $uniformarrayinfo$ } } -$setters$ +$methods$ }; typedef std::shared_ptr<$name$> $name$Ptr; diff --git a/src/tools/shadertool/ShaderTool.cpp b/src/tools/shadertool/ShaderTool.cpp index c653900e7..6fc2a0a72 100644 --- a/src/tools/shadertool/ShaderTool.cpp +++ b/src/tools/shadertool/ShaderTool.cpp @@ -95,6 +95,7 @@ core::AppState ShaderTool::onRunning() { _shaderDirectory = getArgVal("--shaderdir"); _sourceDirectory = getArgVal("--sourcedir", _filesystem->basePath() + "src/modules/" + _namespaceSrc + "/"); + _postfix = getArgVal("--postfix", ""); if (!core::string::endsWith(_shaderDirectory, "/")) { _shaderDirectory = _shaderDirectory + "/"; @@ -138,7 +139,7 @@ core::AppState ShaderTool::onRunning() { } if (!shadertool::generateSrc(templateShader, templateUniformBuffer, _shaderStruct, - filesystem(), _namespaceSrc, _sourceDirectory, _shaderDirectory)) { + filesystem(), _namespaceSrc, _sourceDirectory, _shaderDirectory, _postfix)) { Log::error("Failed to generate shader source for %s", _shaderfile.c_str()); _exitCode = 1; return core::AppState::Cleanup; @@ -199,7 +200,7 @@ core::AppState ShaderTool::onRunning() { } if (!shadertool::generateSrc(templateShader, templateUniformBuffer, _shaderStruct, - filesystem(), _namespaceSrc, _sourceDirectory, _shaderDirectory)) { + filesystem(), _namespaceSrc, _sourceDirectory, _shaderDirectory, _postfix)) { Log::error("Failed to generate shader source for %s", _shaderfile.c_str()); _exitCode = 1; return core::AppState::Cleanup; diff --git a/src/tools/shadertool/ShaderTool.h b/src/tools/shadertool/ShaderTool.h index f7f68d282..7f64ee35b 100644 --- a/src/tools/shadertool/ShaderTool.h +++ b/src/tools/shadertool/ShaderTool.h @@ -19,6 +19,7 @@ protected: ShaderStruct _shaderStruct; std::string _namespaceSrc; std::string _sourceDirectory; + std::string _postfix; std::string _shaderDirectory; std::string _shaderTemplateFile; std::string _glslangValidatorBin; diff --git a/src/tools/shadertool/Types.h b/src/tools/shadertool/Types.h index 13d72183f..9821dbcaf 100644 --- a/src/tools/shadertool/Types.h +++ b/src/tools/shadertool/Types.h @@ -23,18 +23,6 @@ enum class BlockLayout { std430 }; -enum class PrimitiveType { - None, - Points, - Lines, - LinesAdjacency, - Triangles, - TrianglesAdjacency, - LineStrip, - TriangleStrip, - Max -}; - struct Variable { enum Type { DOUBLE = 0, FLOAT, UNSIGNED_INT, INT, BOOL, @@ -93,7 +81,7 @@ struct Layout { bool pixelCenterInteger = false; // 4.0 bool earlyFragmentTests = false; // 4.2 glm::ivec3 localSize { -1 }; - PrimitiveType primitiveType = PrimitiveType::None; + video::Primitive primitiveType = video::Primitive::Max; BlockLayout blockLayout = BlockLayout::unknown; video::ImageFormat imageFormat = video::ImageFormat::Max; @@ -110,12 +98,21 @@ struct ImageFormatType { const char* ctype; }; +struct PrimitiveType { + video::Primitive type; + const char* str; +}; + struct UniformBlock { std::string name; std::vector members; Layout layout; }; +struct InOut { + Layout layout; +}; + struct ShaderStruct { std::string name; std::string filename; @@ -129,4 +126,6 @@ struct ShaderStruct { std::vector varyings; // fragment only std::vector outs; + InOut in; + InOut out; }; diff --git a/src/tools/shadertool/UniformBufferTemplate.h.in b/src/tools/shadertool/UniformBufferTemplate.h.in index 502a34c73..2ab9beb97 100644 --- a/src/tools/shadertool/UniformBufferTemplate.h.in +++ b/src/tools/shadertool/UniformBufferTemplate.h.in @@ -21,7 +21,7 @@ $uniformbuffers$ void shutdown() { $shutdown$ } -$setters$ +$methods$ }; }; diff --git a/src/tools/shadertool/Util.cpp b/src/tools/shadertool/Util.cpp index a2209dfd5..dc0eef013 100644 --- a/src/tools/shadertool/Util.cpp +++ b/src/tools/shadertool/Util.cpp @@ -143,6 +143,29 @@ const char* getImageFormatTypeString(video::ImageFormat format) { return nullptr; } +#define PRIMITVEENTRY(x) {video::Primitive::x, #x} +static const PrimitiveType cPrimitiveType[] = { + PRIMITVEENTRY(Points), + PRIMITVEENTRY(Lines), + PRIMITVEENTRY(LinesAdjacency), + PRIMITVEENTRY(Triangles), + PRIMITVEENTRY(TrianglesAdjacency), + PRIMITVEENTRY(LineStrip), + PRIMITVEENTRY(TriangleStrip) +}; +#undef PRIMITVEENTRY +static_assert((size_t)video::Primitive::Max == lengthof(cPrimitiveType), "mismatch in primitive types"); + +const char* getPrimitiveTypeString(video::Primitive primitive) { + const int max = std::enum_value(video::Primitive::Max); + for (int i = 0; i < max; ++i) { + if (primitive == cPrimitiveType[i].type) { + return cPrimitiveType[i].str; + } + } + return nullptr; +} + std::string uniformSetterPostfix(const Variable::Type type, int amount) { switch (type) { case Variable::MAX: diff --git a/src/tools/shadertool/Util.h b/src/tools/shadertool/Util.h index 4f38418e2..9f3330feb 100644 --- a/src/tools/shadertool/Util.h +++ b/src/tools/shadertool/Util.h @@ -30,6 +30,8 @@ extern video::ImageFormat getImageFormat(const std::string& type, int line); extern const char* getImageFormatGLType(video::ImageFormat format); extern const char* getImageFormatTypeString(video::ImageFormat format); +extern const char* getPrimitiveTypeString(video::Primitive primitive); + extern int getComponents(const Variable::Type type); extern Variable::Type getType(const std::string& type, int line);