1+ /*
2+ * Copyright (c) 2009-2026 jMonkeyEngine
3+ * All rights reserved.
4+ *
5+ * Redistribution and use in source and binary forms, with or without
6+ * modification, are permitted provided that the following conditions are
7+ * met:
8+ *
9+ * * Redistributions of source code must retain the above copyright
10+ * notice, this list of conditions and the following disclaimer.
11+ *
12+ * * Redistributions in binary form must reproduce the above copyright
13+ * notice, this list of conditions and the following disclaimer in the
14+ * documentation and/or other materials provided with the distribution.
15+ *
16+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17+ * may be used to endorse or promote products derived from this software
18+ * without specific prior written permission.
19+ *
20+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+ package com .jme3 .renderer .opengl ;
33+
34+ import com .jme3 .math .Matrix4f ;
35+ import com .jme3 .math .Vector2f ;
36+ import com .jme3 .math .Vector3f ;
37+ import com .jme3 .math .Vector4f ;
38+ import com .jme3 .renderer .RendererException ;
39+ import com .jme3 .util .BufferUtils ;
40+ import com .jme3 .util .NativeObject ;
41+
42+ import java .nio .FloatBuffer ;
43+ import java .nio .IntBuffer ;
44+
45+ /**
46+ * A compute shader for general-purpose GPU computing (GPGPU).
47+ * <p>
48+ * Compute shaders require OpenGL 4.3 or higher.
49+ */
50+ public class ComputeShader extends NativeObject {
51+
52+ private final GL4 gl ;
53+ private final String source ;
54+ /**
55+ * Creates a new compute shader from GLSL source code.
56+ */
57+ public ComputeShader (GL4 gl , String source ) {
58+ super ();
59+ this .gl = gl ;
60+ this .source = source ;
61+ //Load this upfront to surface any problems at init time
62+ createComputeShader ();
63+ }
64+ private ComputeShader (ComputeShader source ){
65+ super ();
66+ this .gl = source .gl ;
67+ this .id = source .id ;
68+ this .source = null ;
69+ }
70+
71+ private void createComputeShader (){
72+ // Create and compile the shader
73+ int shaderId = gl .glCreateShader (GL4 .GL_COMPUTE_SHADER );
74+ if (shaderId <= 0 ) {
75+ throw new RendererException ("Failed to create compute shader" );
76+ }
77+
78+ IntBuffer intBuf = BufferUtils .createIntBuffer (1 );
79+ intBuf .clear ();
80+ intBuf .put (0 , source .length ());
81+ gl .glShaderSource (shaderId , new String []{source }, intBuf );
82+ gl .glCompileShader (shaderId );
83+
84+ // Check compilation status
85+ gl .glGetShader (shaderId , GL .GL_COMPILE_STATUS , intBuf );
86+ if (intBuf .get (0 ) != GL .GL_TRUE ) {
87+ gl .glGetShader (shaderId , GL .GL_INFO_LOG_LENGTH , intBuf );
88+ String infoLog = gl .glGetShaderInfoLog (shaderId , intBuf .get (0 ));
89+ gl .glDeleteShader (shaderId );
90+ throw new RendererException ("Compute shader compilation failed: " + infoLog );
91+ }
92+
93+ // Create program and link
94+ id = gl .glCreateProgram ();
95+ if (id <= 0 ) {
96+ gl .glDeleteShader (shaderId );
97+ throw new RendererException ("Failed to create shader program" );
98+ }
99+
100+ gl .glAttachShader (id , shaderId );
101+ gl .glLinkProgram (id );
102+
103+ // Check link status
104+ gl .glGetProgram (id , GL .GL_LINK_STATUS , intBuf );
105+ if (intBuf .get (0 ) != GL .GL_TRUE ) {
106+ gl .glGetProgram (id , GL .GL_INFO_LOG_LENGTH , intBuf );
107+ String infoLog = gl .glGetProgramInfoLog (id , intBuf .get (0 ));
108+ gl .glDeleteShader (shaderId );
109+ gl .glDeleteProgram (id );
110+ throw new RendererException ("Compute shader program linking failed: " + infoLog );
111+ }
112+
113+ // Shader object can be deleted after linking
114+ gl .glDeleteShader (shaderId );
115+
116+ clearUpdateNeeded ();
117+ }
118+
119+ /**
120+ * Activates this compute shader for use.
121+ * Must be called before setting uniforms or dispatching.
122+ */
123+ public void makeActive () {
124+ if (isUpdateNeeded ()){
125+ createComputeShader ();
126+ }
127+ gl .glUseProgram (id );
128+ }
129+
130+ /**
131+ * Dispatches the compute shader with the specified number of work groups.
132+ */
133+ public void dispatch (int numGroupsX , int numGroupsY , int numGroupsZ ) {
134+ gl .glDispatchCompute (numGroupsX , numGroupsY , numGroupsZ );
135+ }
136+
137+ public void setUniform (int location , int value ) {
138+ gl .glUniform1i (location , value );
139+ }
140+
141+ public void setUniform (int location , float value ) {
142+ gl .glUniform1f (location , value );
143+ }
144+
145+ public void setUniform (int location , Vector2f value ) {
146+ gl .glUniform2f (location , value .x , value .y );
147+ }
148+
149+ public void setUniform (int location , Vector3f value ) {
150+ gl .glUniform3f (location , value .x , value .y , value .z );
151+ }
152+
153+ public void setUniform (int location , Vector4f value ) {
154+ gl .glUniform4f (location , value .x , value .y , value .z , value .w );
155+ }
156+
157+ public void setUniform (int location , Matrix4f value ) {
158+ FloatBuffer floatBuf16 = BufferUtils .createFloatBuffer (16 );
159+ value .fillFloatBuffer (floatBuf16 , true );
160+ floatBuf16 .clear ();
161+ gl .glUniformMatrix4 (location , false , floatBuf16 );
162+ }
163+
164+ public int getUniformLocation (String name ) {
165+ return gl .glGetUniformLocation (id , name );
166+ }
167+
168+ public void bindShaderStorageBuffer (int location , ShaderStorageBufferObject ssbo ) {
169+ gl .glBindBufferBase (GL4 .GL_SHADER_STORAGE_BUFFER , location , ssbo .getId ());
170+ }
171+
172+ @ Override
173+ public void resetObject () {
174+ id = INVALID_ID ;
175+ setUpdateNeeded ();
176+ }
177+
178+ @ Override
179+ public void deleteObject (Object rendererObject ) {
180+ if (id != INVALID_ID ){
181+ gl .glDeleteProgram (id );
182+ }
183+ resetObject ();
184+ }
185+
186+ @ Override
187+ public NativeObject createDestructableClone () {
188+ return new ComputeShader (this );
189+ }
190+
191+ @ Override
192+ public long getUniqueId () {
193+ //Note this is the same type of ID as a regular shader.
194+ return ((long )OBJTYPE_SHADER << 32 ) | (0xffffffffL & (long )id );
195+ }
196+ }
0 commit comments