From bcd8a81ba5e58745e6839efb7b8fab13367e9a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 11 Jan 2016 00:33:13 +0100 Subject: [PATCH] Implemented ARB_compute_shader. The test fails somehow, but too tired to fix anything now. --- doc/opengl-mapping.dox | 2 +- doc/opengl-support.dox | 2 +- src/Magnum/AbstractShaderProgram.cpp | 7 ++ src/Magnum/AbstractShaderProgram.h | 22 +++++ .../Test/AbstractShaderProgramGLTest.cpp | 91 ++++++++++++++++++- .../ComputeShader.comp | 7 ++ .../resources.conf | 3 + 7 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 src/Magnum/Test/AbstractShaderProgramGLTestFiles/ComputeShader.comp diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 998984a54..4a061aedb 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -121,7 +121,7 @@ OpenGL function | Matching API @fn_gl{DepthRangeArray} | | @fn_gl{DepthRangeIndexed} | | @fn_gl{DetachShader} | | -@fn_gl{DispatchCompute} | | +@fn_gl{DispatchCompute} | @ref AbstractShaderProgram::DispatchCompute() @fn_gl_extension{DispatchComputeGroupSize,ARB,compute_variable_group_size} | | @fn_gl{DispatchComputeIndirect} | | @fn_gl{DrawArrays}, \n @fn_gl{DrawArraysInstanced}, \n @fn_gl{DrawArraysInstancedBaseInstance}, \n @fn_gl{DrawElements}, \n @fn_gl{DrawRangeElements}, \n @fn_gl{DrawElementsBaseVertex}, \n @fn_gl{DrawRangeElementsBaseVertex}, \n @fn_gl{DrawElementsInstanced}, \n @fn_gl{DrawElementsInstancedBaseInstance}, \n @fn_gl{DrawElementsInstancedBaseVertex}, \n @fn_gl{DrawElementsInstancedBaseVertexBaseInstance} | @ref Mesh::draw(), \n @ref MeshView::draw() diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index a82eb683e..5b6e6713e 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -173,7 +173,7 @@ GLSL 4.30 | done @extension{ARB,arrays_of_arrays} | done (shading language only) @extension{ARB,ES3_compatibility} | only conservative sample query and compression formats @extension{ARB,clear_buffer_object} | | -@extension{ARB,compute_shader} | | +@extension{ARB,compute_shader} | done except for indirect dispatch @extension{ARB,copy_image} | | @extension{KHR,debug} | missing log retrieval, sync, pipeline and sampler label @extension{ARB,explicit_uniform_location} | done diff --git a/src/Magnum/AbstractShaderProgram.cpp b/src/Magnum/AbstractShaderProgram.cpp index 4ff1b1cd2..b1b41ce8f 100644 --- a/src/Magnum/AbstractShaderProgram.cpp +++ b/src/Magnum/AbstractShaderProgram.cpp @@ -332,6 +332,13 @@ std::pair AbstractShaderProgram::validate() { return {success, std::move(message)}; } +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +void AbstractShaderProgram::dispatchCompute(const Vector3ui& workgroupCount) { + use(); + glDispatchCompute(workgroupCount.x(), workgroupCount.y(), workgroupCount.z()); +} +#endif + void AbstractShaderProgram::use() { /* Use only if the program isn't already in use */ GLuint& current = Context::current().state().shaderProgram->current; diff --git a/src/Magnum/AbstractShaderProgram.h b/src/Magnum/AbstractShaderProgram.h index 9bad054c3..4efb1b7e1 100644 --- a/src/Magnum/AbstractShaderProgram.h +++ b/src/Magnum/AbstractShaderProgram.h @@ -413,6 +413,13 @@ shader.setTransformation(transformation) mesh.draw(shader); @endcode +@anchor AbstractShaderProgram-compute-workflow +## Compute workflow + +Add just the @ref Shader::Type::Compute shader and implement uniform/texture +setting functions as needed. After setting up required parameters call +@ref dispatchCompute(). + @anchor AbstractShaderProgram-types ## Mapping between GLSL and Magnum types @@ -756,6 +763,21 @@ class MAGNUM_EXPORT AbstractShaderProgram: public AbstractObject { */ std::pair validate(); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + /** + * @brief Dispatch compute + * @param workgroupCount Workgroup count in given dimension + * + * Valid only on programs with compute shader attached. + * @see @fn_gl{DispatchCompute} + * @requires_gl43 Extension @extension{ARB,compute_shader} + * @requires_gles31 Compute shaders are not available in OpenGL ES 3.0 + * and older. + * @requires_gles Compute shaders are not available in WebGL. + */ + void dispatchCompute(const Vector3ui& workgroupCount); + #endif + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Use shader for rendering diff --git a/src/Magnum/Test/AbstractShaderProgramGLTest.cpp b/src/Magnum/Test/AbstractShaderProgramGLTest.cpp index 6989508bc..d7ef8831a 100644 --- a/src/Magnum/Test/AbstractShaderProgramGLTest.cpp +++ b/src/Magnum/Test/AbstractShaderProgramGLTest.cpp @@ -29,9 +29,16 @@ #include "Magnum/AbstractShaderProgram.h" #include "Magnum/Context.h" #include "Magnum/Extensions.h" +#include "Magnum/Image.h" +#include "Magnum/ImageView.h" +#include "Magnum/ImageFormat.h" +#include "Magnum/PixelFormat.h" #include "Magnum/Shader.h" +#include "Magnum/Texture.h" +#include "Magnum/TextureFormat.h" #include "Magnum/Math/Matrix.h" #include "Magnum/Math/Vector4.h" +#include "Magnum/Math/Color.h" #include "Magnum/Test/AbstractOpenGLTester.h" namespace Magnum { namespace Test { @@ -62,6 +69,8 @@ struct AbstractShaderProgramGLTest: AbstractOpenGLTester { void uniformBlockIndexNotFound(); void uniformBlock(); #endif + + void compute(); }; AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() { @@ -86,7 +95,9 @@ AbstractShaderProgramGLTest::AbstractShaderProgramGLTest() { #ifndef MAGNUM_TARGET_GLES2 &AbstractShaderProgramGLTest::createUniformBlocks, &AbstractShaderProgramGLTest::uniformBlockIndexNotFound, - &AbstractShaderProgramGLTest::uniformBlock + &AbstractShaderProgramGLTest::uniformBlock, + + &AbstractShaderProgramGLTest::compute #endif }); } @@ -628,6 +639,84 @@ void AbstractShaderProgramGLTest::uniformBlock() { MAGNUM_VERIFY_NO_ERROR(); } + +void AbstractShaderProgramGLTest::compute() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::compute_shader::string() + std::string(" is not supported.")); + #else + if(!Context::current().isVersionSupported(Version::GLES310)) + CORRADE_SKIP("OpenGL ES 3.1 is not supported."); + #endif + + struct ComputeShader: AbstractShaderProgram { + explicit ComputeShader() { + Utility::Resource rs("AbstractShaderProgramGLTest"); + + Shader compute( + #ifndef MAGNUM_TARGET_GLES + Version::GL430, + #else + Version::GLES310, + #endif + Shader::Type::Compute); + compute.addSource(rs.get("ComputeShader.comp")); + CORRADE_INTERNAL_ASSERT(compute.compile()); + + attachShader(compute); + link(); + } + + ComputeShader& setImages(Texture2D& input, Texture2D& output) { + input.bindImage(0, 0, ImageAccess::ReadOnly, ImageFormat::RGBA8UI); + output.bindImage(1, 0, ImageAccess::WriteOnly, ImageFormat::RGBA8UI); + return *this; + } + } shader; + + MAGNUM_VERIFY_NO_ERROR(); + + const Color4ub inData[] = { + { 10, 20, 30, 40}, + { 50, 60, 70, 80}, + { 90, 100, 110, 120}, + {130, 140, 150, 160} + }; + + #ifndef MAGNUM_TARGET_GLES + const Color4ub outData[] = { + { 15, 30, 45, 60}, + { 75, 90, 105, 120}, + {135, 150, 165, 180}, + {195, 210, 225, 240} + }; + #endif + + Texture2D in; + in.setStorage(1, TextureFormat::RGBA8UI, {2, 2}) + .setSubImage(0, {}, ImageView2D{PixelFormat::RGBAInteger, PixelType::UnsignedByte, {2, 2}, inData}); + + Texture2D out; + out.setStorage(1, TextureFormat::RGBA8UI, {2, 2}); + + MAGNUM_VERIFY_NO_ERROR(); + + shader.setImages(in, out) + .dispatchCompute({1, 1, 1}); + + MAGNUM_VERIFY_NO_ERROR(); + + /** @todo Test on ES */ + #ifndef MAGNUM_TARGET_GLES + const auto data = out.image(0, {PixelFormat::RGBAInteger, PixelType::UnsignedByte}).data(); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE( + (Corrade::Containers::ArrayView{reinterpret_cast(data.data()), 4}), + (Corrade::Containers::ArrayView{outData})); + #endif +} #endif }} diff --git a/src/Magnum/Test/AbstractShaderProgramGLTestFiles/ComputeShader.comp b/src/Magnum/Test/AbstractShaderProgramGLTestFiles/ComputeShader.comp new file mode 100644 index 000000000..8328717c1 --- /dev/null +++ b/src/Magnum/Test/AbstractShaderProgramGLTestFiles/ComputeShader.comp @@ -0,0 +1,7 @@ +layout(local_size_x = 2, local_size_y = 2) in; +layout(binding = 0, rgba8ui) uniform mediump uimage2D inData; +layout(binding = 1, rgba8ui) uniform mediump uimage2D outData; + +void main() { + imageStore(outData, ivec2(gl_GlobalInvocationID.xy), imageLoad(inData, ivec2(gl_GlobalInvocationID.xy))*3u/2u); +} diff --git a/src/Magnum/Test/AbstractShaderProgramGLTestFiles/resources.conf b/src/Magnum/Test/AbstractShaderProgramGLTestFiles/resources.conf index 4bcbfb585..16f02a005 100644 --- a/src/Magnum/Test/AbstractShaderProgramGLTestFiles/resources.conf +++ b/src/Magnum/Test/AbstractShaderProgramGLTestFiles/resources.conf @@ -14,3 +14,6 @@ filename=UniformBlockShader.frag [file] filename=UniformBlockShader.vert + +[file] +filename=ComputeShader.comp