Shader.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * Copyright (c) 2022, Stephan Unverwerth <s.unverwerth@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Debug.h>
  7. #include <AK/StringBuilder.h>
  8. #include <LibGL/GLContext.h>
  9. namespace GL {
  10. GLuint GLContext::gl_create_shader(GLenum shader_type)
  11. {
  12. // FIXME: Add support for GL_COMPUTE_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER and GL_GEOMETRY_SHADER.
  13. RETURN_VALUE_WITH_ERROR_IF(shader_type != GL_VERTEX_SHADER
  14. && shader_type != GL_FRAGMENT_SHADER,
  15. GL_INVALID_ENUM,
  16. 0);
  17. GLuint shader_name;
  18. m_shader_name_allocator.allocate(1, &shader_name);
  19. auto shader = Shader::create(shader_type);
  20. m_allocated_shaders.set(shader_name, shader);
  21. return shader_name;
  22. }
  23. void GLContext::gl_delete_shader(GLuint shader)
  24. {
  25. // "A value of 0 for shader will be silently ignored." (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDeleteShader.xhtml)
  26. if (shader == 0)
  27. return;
  28. auto it = m_allocated_shaders.find(shader);
  29. RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_VALUE);
  30. // FIXME: According to the spec, we should only flag the shader for deletion here and delete it once it is detached from all programs.
  31. m_allocated_shaders.remove(it);
  32. m_shader_name_allocator.free(shader);
  33. }
  34. void GLContext::gl_shader_source(GLuint shader, GLsizei count, GLchar const** string, GLint const* length)
  35. {
  36. auto it = m_allocated_shaders.find(shader);
  37. // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL."
  38. RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION);
  39. RETURN_WITH_ERROR_IF(count < 0, GL_INVALID_VALUE);
  40. it->value->clear_sources();
  41. for (int i = 0; i < count; i++) {
  42. if (length == nullptr || length[i] < 0) {
  43. auto result = it->value->add_source(StringView(string[i], strlen(string[i])));
  44. RETURN_WITH_ERROR_IF(result.is_error() && result.error().is_errno() && result.error().code() == ENOMEM, GL_OUT_OF_MEMORY);
  45. RETURN_WITH_ERROR_IF(result.is_error(), GL_INVALID_OPERATION);
  46. } else {
  47. auto result = it->value->add_source(StringView(string[i], length[i]));
  48. RETURN_WITH_ERROR_IF(result.is_error() && result.error().is_errno() && result.error().code() == ENOMEM, GL_OUT_OF_MEMORY);
  49. RETURN_WITH_ERROR_IF(result.is_error(), GL_INVALID_OPERATION);
  50. }
  51. }
  52. }
  53. void GLContext::gl_compile_shader(GLuint shader)
  54. {
  55. auto it = m_allocated_shaders.find(shader);
  56. // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL."
  57. RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION);
  58. // NOTE: We are ignoring the compilation result here since it is tracked inside the shader object
  59. (void)it->value->compile();
  60. }
  61. void GLContext::gl_get_shader(GLuint shader, GLenum pname, GLint* params)
  62. {
  63. RETURN_WITH_ERROR_IF(pname != GL_SHADER_TYPE
  64. && pname != GL_DELETE_STATUS
  65. && pname != GL_COMPILE_STATUS
  66. && pname != GL_INFO_LOG_LENGTH
  67. && pname != GL_SHADER_SOURCE_LENGTH,
  68. GL_INVALID_ENUM);
  69. // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL."
  70. // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, or GL_SHADER_SOURCE_LENGTH but a shader compiler is not supported."
  71. auto it = m_allocated_shaders.find(shader);
  72. RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION);
  73. switch (pname) {
  74. case GL_SHADER_TYPE:
  75. *params = it->value->type();
  76. break;
  77. case GL_DELETE_STATUS:
  78. // FIXME: Return the actual delete status once we implement this missing feature
  79. *params = GL_FALSE;
  80. break;
  81. case GL_COMPILE_STATUS:
  82. *params = it->value->compile_status() ? GL_TRUE : GL_FALSE;
  83. break;
  84. case GL_INFO_LOG_LENGTH:
  85. *params = it->value->info_log_length();
  86. break;
  87. case GL_SHADER_SOURCE_LENGTH:
  88. *params = it->value->combined_source_length();
  89. break;
  90. default:
  91. VERIFY_NOT_REACHED();
  92. }
  93. }
  94. GLuint GLContext::gl_create_program()
  95. {
  96. GLuint program_name;
  97. m_program_name_allocator.allocate(1, &program_name);
  98. auto program = Program::create();
  99. m_allocated_programs.set(program_name, program);
  100. return program_name;
  101. }
  102. void GLContext::gl_delete_program(GLuint program)
  103. {
  104. // "A value of 0 for program will be silently ignored." (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDeleteProgram.xhtml)
  105. if (program == 0)
  106. return;
  107. auto it = m_allocated_programs.find(program);
  108. RETURN_WITH_ERROR_IF(it == m_allocated_programs.end(), GL_INVALID_VALUE);
  109. // FIXME: According to the spec, we should only flag the program for deletion here and delete it once it is not used anymore.
  110. m_allocated_programs.remove(it);
  111. m_program_name_allocator.free(program);
  112. }
  113. void GLContext::gl_attach_shader(GLuint program, GLuint shader)
  114. {
  115. auto program_it = m_allocated_programs.find(program);
  116. auto shader_it = m_allocated_shaders.find(shader);
  117. // FIXME: implement check "GL_INVALID_VALUE is generated if either program or shader is not a value generated by OpenGL."
  118. RETURN_WITH_ERROR_IF(program_it == m_allocated_programs.end(), GL_INVALID_OPERATION);
  119. RETURN_WITH_ERROR_IF(shader_it == m_allocated_shaders.end(), GL_INVALID_OPERATION);
  120. // NOTE: attach_result is Error if the shader is already attached to this program
  121. auto attach_result = program_it->value->attach_shader(*shader_it->value);
  122. RETURN_WITH_ERROR_IF(attach_result.is_error() && attach_result.error().is_errno() && attach_result.error().code() == ENOMEM, GL_OUT_OF_MEMORY);
  123. RETURN_WITH_ERROR_IF(attach_result.is_error(), GL_INVALID_OPERATION);
  124. }
  125. void GLContext::gl_link_program(GLuint program)
  126. {
  127. auto program_it = m_allocated_programs.find(program);
  128. // FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL."
  129. RETURN_WITH_ERROR_IF(program_it == m_allocated_programs.end(), GL_INVALID_OPERATION);
  130. // FIXME: implement check "GL_INVALID_OPERATION is generated if program is the currently active program object and transform feedback mode is active."
  131. // NOTE: We are ignoring the link result since this is tracked inside the program object
  132. (void)program_it->value->link(*m_rasterizer);
  133. }
  134. void GLContext::gl_use_program(GLuint program)
  135. {
  136. if (program == 0) {
  137. m_current_program = nullptr;
  138. return;
  139. }
  140. auto it = m_allocated_programs.find(program);
  141. // FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL."
  142. RETURN_WITH_ERROR_IF(it == m_allocated_programs.end(), GL_INVALID_OPERATION);
  143. // FIXME: implement check "GL_INVALID_OPERATION is generated if transform feedback mode is active."
  144. RETURN_WITH_ERROR_IF(it->value->link_status() != true, GL_INVALID_OPERATION);
  145. m_current_program = it->value;
  146. }
  147. void GLContext::gl_get_program(GLuint program, GLenum pname, GLint* params)
  148. {
  149. auto it = m_allocated_programs.find(program);
  150. // FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL."
  151. RETURN_WITH_ERROR_IF(it == m_allocated_programs.end(), GL_INVALID_OPERATION);
  152. // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_GEOMETRY_VERTICES_OUT, GL_GEOMETRY_INPUT_TYPE, or GL_GEOMETRY_OUTPUT_TYPE, and program does not contain a geometry shader."
  153. // FIXME: implement all the other allowed pname values (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetProgram.xhtml)
  154. RETURN_WITH_ERROR_IF(pname != GL_DELETE_STATUS
  155. && pname != GL_LINK_STATUS
  156. && pname != GL_INFO_LOG_LENGTH,
  157. GL_INVALID_ENUM);
  158. // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_COMPUTE_WORK_GROUP_SIZE and program does not contain a binary for the compute shader stage."
  159. switch (pname) {
  160. case GL_DELETE_STATUS:
  161. // FIXME: Return the actual delete status once we implement this missing feature
  162. *params = GL_FALSE;
  163. break;
  164. case GL_LINK_STATUS:
  165. *params = it->value->link_status() ? GL_TRUE : GL_FALSE;
  166. break;
  167. case GL_INFO_LOG_LENGTH:
  168. *params = it->value->info_log_length();
  169. break;
  170. default:
  171. VERIFY_NOT_REACHED();
  172. }
  173. }
  174. }