Stencil.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
  3. * Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
  4. * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <LibGL/GLContext.h>
  9. namespace GL {
  10. void GLContext::gl_clear_stencil(GLint s)
  11. {
  12. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_stencil, s);
  13. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  14. m_clear_stencil = static_cast<u8>(s & ((1 << m_device_info.stencil_bits) - 1));
  15. }
  16. void GLContext::gl_stencil_func_separate(GLenum face, GLenum func, GLint ref, GLuint mask)
  17. {
  18. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_stencil_func_separate, face, func, ref, mask);
  19. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  20. RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM);
  21. RETURN_WITH_ERROR_IF(!(func == GL_NEVER
  22. || func == GL_LESS
  23. || func == GL_LEQUAL
  24. || func == GL_GREATER
  25. || func == GL_GEQUAL
  26. || func == GL_EQUAL
  27. || func == GL_NOTEQUAL
  28. || func == GL_ALWAYS),
  29. GL_INVALID_ENUM);
  30. ref = clamp(ref, 0, (1 << m_device_info.stencil_bits) - 1);
  31. StencilFunctionOptions new_options = { func, ref, mask };
  32. if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
  33. m_stencil_function[Face::Front] = new_options;
  34. if (face == GL_BACK || face == GL_FRONT_AND_BACK)
  35. m_stencil_function[Face::Back] = new_options;
  36. m_stencil_configuration_dirty = true;
  37. }
  38. void GLContext::gl_stencil_mask_separate(GLenum face, GLuint mask)
  39. {
  40. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_stencil_mask_separate, face, mask);
  41. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  42. if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
  43. m_stencil_operation[Face::Front].write_mask = mask;
  44. if (face == GL_BACK || face == GL_FRONT_AND_BACK)
  45. m_stencil_operation[Face::Back].write_mask = mask;
  46. m_stencil_configuration_dirty = true;
  47. }
  48. void GLContext::gl_stencil_op_separate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)
  49. {
  50. APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_stencil_op_separate, face, sfail, dpfail, dppass);
  51. RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
  52. RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM);
  53. auto is_valid_op = [](GLenum op) -> bool {
  54. return op == GL_KEEP || op == GL_ZERO || op == GL_REPLACE || op == GL_INCR || op == GL_INCR_WRAP
  55. || op == GL_DECR || op == GL_DECR_WRAP || op == GL_INVERT;
  56. };
  57. RETURN_WITH_ERROR_IF(!is_valid_op(sfail), GL_INVALID_ENUM);
  58. RETURN_WITH_ERROR_IF(!is_valid_op(dpfail), GL_INVALID_ENUM);
  59. RETURN_WITH_ERROR_IF(!is_valid_op(dppass), GL_INVALID_ENUM);
  60. auto update_stencil_operation = [&](Face face, GLenum sfail, GLenum dpfail, GLenum dppass) {
  61. auto& stencil_operation = m_stencil_operation[face];
  62. stencil_operation.op_fail = sfail;
  63. stencil_operation.op_depth_fail = dpfail;
  64. stencil_operation.op_pass = dppass;
  65. };
  66. if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
  67. update_stencil_operation(Face::Front, sfail, dpfail, dppass);
  68. if (face == GL_BACK || face == GL_FRONT_AND_BACK)
  69. update_stencil_operation(Face::Back, sfail, dpfail, dppass);
  70. m_stencil_configuration_dirty = true;
  71. }
  72. void GLContext::sync_stencil_configuration()
  73. {
  74. if (!m_stencil_configuration_dirty)
  75. return;
  76. m_stencil_configuration_dirty = false;
  77. auto set_device_stencil = [&](GPU::Face face, StencilFunctionOptions func, StencilOperationOptions op) {
  78. GPU::StencilConfiguration device_configuration;
  79. // Stencil test function
  80. auto map_func = [](GLenum func) -> GPU::StencilTestFunction {
  81. switch (func) {
  82. case GL_ALWAYS:
  83. return GPU::StencilTestFunction::Always;
  84. case GL_EQUAL:
  85. return GPU::StencilTestFunction::Equal;
  86. case GL_GEQUAL:
  87. return GPU::StencilTestFunction::GreaterOrEqual;
  88. case GL_GREATER:
  89. return GPU::StencilTestFunction::Greater;
  90. case GL_LESS:
  91. return GPU::StencilTestFunction::Less;
  92. case GL_LEQUAL:
  93. return GPU::StencilTestFunction::LessOrEqual;
  94. case GL_NEVER:
  95. return GPU::StencilTestFunction::Never;
  96. case GL_NOTEQUAL:
  97. return GPU::StencilTestFunction::NotEqual;
  98. }
  99. VERIFY_NOT_REACHED();
  100. };
  101. device_configuration.test_function = map_func(func.func);
  102. device_configuration.reference_value = func.reference_value;
  103. device_configuration.test_mask = func.mask;
  104. // Stencil operation
  105. auto map_operation = [](GLenum operation) -> GPU::StencilOperation {
  106. switch (operation) {
  107. case GL_DECR:
  108. return GPU::StencilOperation::Decrement;
  109. case GL_DECR_WRAP:
  110. return GPU::StencilOperation::DecrementWrap;
  111. case GL_INCR:
  112. return GPU::StencilOperation::Increment;
  113. case GL_INCR_WRAP:
  114. return GPU::StencilOperation::IncrementWrap;
  115. case GL_INVERT:
  116. return GPU::StencilOperation::Invert;
  117. case GL_KEEP:
  118. return GPU::StencilOperation::Keep;
  119. case GL_REPLACE:
  120. return GPU::StencilOperation::Replace;
  121. case GL_ZERO:
  122. return GPU::StencilOperation::Zero;
  123. }
  124. VERIFY_NOT_REACHED();
  125. };
  126. device_configuration.on_stencil_test_fail = map_operation(op.op_fail);
  127. device_configuration.on_depth_test_fail = map_operation(op.op_depth_fail);
  128. device_configuration.on_pass = map_operation(op.op_pass);
  129. device_configuration.write_mask = op.write_mask;
  130. m_rasterizer->set_stencil_configuration(face, device_configuration);
  131. };
  132. set_device_stencil(GPU::Face::Front, m_stencil_function[Face::Front], m_stencil_operation[Face::Front]);
  133. set_device_stencil(GPU::Face::Back, m_stencil_function[Face::Back], m_stencil_operation[Face::Back]);
  134. }
  135. }