Serenity Operating System
at master 159 lines 6.5 kB view raw
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 9#include <LibGL/GLContext.h> 10 11namespace GL { 12 13void GLContext::gl_clear_stencil(GLint s) 14{ 15 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clear_stencil, s); 16 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 17 18 m_clear_stencil = static_cast<u8>(s & ((1 << m_device_info.stencil_bits) - 1)); 19} 20 21void GLContext::gl_stencil_func_separate(GLenum face, GLenum func, GLint ref, GLuint mask) 22{ 23 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_stencil_func_separate, face, func, ref, mask); 24 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 25 26 RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM); 27 28 RETURN_WITH_ERROR_IF(!(func == GL_NEVER 29 || func == GL_LESS 30 || func == GL_LEQUAL 31 || func == GL_GREATER 32 || func == GL_GEQUAL 33 || func == GL_EQUAL 34 || func == GL_NOTEQUAL 35 || func == GL_ALWAYS), 36 GL_INVALID_ENUM); 37 38 ref = clamp(ref, 0, (1 << m_device_info.stencil_bits) - 1); 39 40 StencilFunctionOptions new_options = { func, ref, mask }; 41 if (face == GL_FRONT || face == GL_FRONT_AND_BACK) 42 m_stencil_function[Face::Front] = new_options; 43 if (face == GL_BACK || face == GL_FRONT_AND_BACK) 44 m_stencil_function[Face::Back] = new_options; 45 46 m_stencil_configuration_dirty = true; 47} 48 49void GLContext::gl_stencil_mask_separate(GLenum face, GLuint mask) 50{ 51 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_stencil_mask_separate, face, mask); 52 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 53 54 if (face == GL_FRONT || face == GL_FRONT_AND_BACK) 55 m_stencil_operation[Face::Front].write_mask = mask; 56 if (face == GL_BACK || face == GL_FRONT_AND_BACK) 57 m_stencil_operation[Face::Back].write_mask = mask; 58 59 m_stencil_configuration_dirty = true; 60} 61 62void GLContext::gl_stencil_op_separate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) 63{ 64 APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_stencil_op_separate, face, sfail, dpfail, dppass); 65 RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); 66 67 RETURN_WITH_ERROR_IF(!(face == GL_FRONT || face == GL_BACK || face == GL_FRONT_AND_BACK), GL_INVALID_ENUM); 68 69 auto is_valid_op = [](GLenum op) -> bool { 70 return op == GL_KEEP || op == GL_ZERO || op == GL_REPLACE || op == GL_INCR || op == GL_INCR_WRAP 71 || op == GL_DECR || op == GL_DECR_WRAP || op == GL_INVERT; 72 }; 73 RETURN_WITH_ERROR_IF(!is_valid_op(sfail), GL_INVALID_ENUM); 74 RETURN_WITH_ERROR_IF(!is_valid_op(dpfail), GL_INVALID_ENUM); 75 RETURN_WITH_ERROR_IF(!is_valid_op(dppass), GL_INVALID_ENUM); 76 77 auto update_stencil_operation = [&](Face face, GLenum sfail, GLenum dpfail, GLenum dppass) { 78 auto& stencil_operation = m_stencil_operation[face]; 79 stencil_operation.op_fail = sfail; 80 stencil_operation.op_depth_fail = dpfail; 81 stencil_operation.op_pass = dppass; 82 }; 83 if (face == GL_FRONT || face == GL_FRONT_AND_BACK) 84 update_stencil_operation(Face::Front, sfail, dpfail, dppass); 85 if (face == GL_BACK || face == GL_FRONT_AND_BACK) 86 update_stencil_operation(Face::Back, sfail, dpfail, dppass); 87 88 m_stencil_configuration_dirty = true; 89} 90 91void GLContext::sync_stencil_configuration() 92{ 93 if (!m_stencil_configuration_dirty) 94 return; 95 m_stencil_configuration_dirty = false; 96 97 auto set_device_stencil = [&](GPU::Face face, StencilFunctionOptions func, StencilOperationOptions op) { 98 GPU::StencilConfiguration device_configuration; 99 100 // Stencil test function 101 auto map_func = [](GLenum func) -> GPU::StencilTestFunction { 102 switch (func) { 103 case GL_ALWAYS: 104 return GPU::StencilTestFunction::Always; 105 case GL_EQUAL: 106 return GPU::StencilTestFunction::Equal; 107 case GL_GEQUAL: 108 return GPU::StencilTestFunction::GreaterOrEqual; 109 case GL_GREATER: 110 return GPU::StencilTestFunction::Greater; 111 case GL_LESS: 112 return GPU::StencilTestFunction::Less; 113 case GL_LEQUAL: 114 return GPU::StencilTestFunction::LessOrEqual; 115 case GL_NEVER: 116 return GPU::StencilTestFunction::Never; 117 case GL_NOTEQUAL: 118 return GPU::StencilTestFunction::NotEqual; 119 } 120 VERIFY_NOT_REACHED(); 121 }; 122 device_configuration.test_function = map_func(func.func); 123 device_configuration.reference_value = func.reference_value; 124 device_configuration.test_mask = func.mask; 125 126 // Stencil operation 127 auto map_operation = [](GLenum operation) -> GPU::StencilOperation { 128 switch (operation) { 129 case GL_DECR: 130 return GPU::StencilOperation::Decrement; 131 case GL_DECR_WRAP: 132 return GPU::StencilOperation::DecrementWrap; 133 case GL_INCR: 134 return GPU::StencilOperation::Increment; 135 case GL_INCR_WRAP: 136 return GPU::StencilOperation::IncrementWrap; 137 case GL_INVERT: 138 return GPU::StencilOperation::Invert; 139 case GL_KEEP: 140 return GPU::StencilOperation::Keep; 141 case GL_REPLACE: 142 return GPU::StencilOperation::Replace; 143 case GL_ZERO: 144 return GPU::StencilOperation::Zero; 145 } 146 VERIFY_NOT_REACHED(); 147 }; 148 device_configuration.on_stencil_test_fail = map_operation(op.op_fail); 149 device_configuration.on_depth_test_fail = map_operation(op.op_depth_fail); 150 device_configuration.on_pass = map_operation(op.op_pass); 151 device_configuration.write_mask = op.write_mask; 152 153 m_rasterizer->set_stencil_configuration(face, device_configuration); 154 }; 155 set_device_stencil(GPU::Face::Front, m_stencil_function[Face::Front], m_stencil_operation[Face::Front]); 156 set_device_stencil(GPU::Face::Back, m_stencil_function[Face::Back], m_stencil_operation[Face::Back]); 157} 158 159}