From 29bbf56286701d622904f67900919a1095153706 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Sat, 8 Jan 2022 14:43:03 +0100 Subject: [PATCH] LibGL+LibSoftGPU: Implement viewport support This implements the `glViewport` API call, the coordinate transformation and the `GL_VIEWPORT` context parameter. --- .../Libraries/LibGL/SoftwareGLContext.cpp | 25 +++++++++++++++---- Userland/Libraries/LibGL/SoftwareGLContext.h | 2 ++ Userland/Libraries/LibSoftGPU/Device.cpp | 18 +++++++------ Userland/Libraries/LibSoftGPU/Device.h | 1 + 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.cpp b/Userland/Libraries/LibGL/SoftwareGLContext.cpp index 8e61cc03bf..747e9ba6de 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.cpp +++ b/Userland/Libraries/LibGL/SoftwareGLContext.cpp @@ -56,7 +56,8 @@ static constexpr size_t TEXTURE_MATRIX_STACK_LIMIT = 8; } SoftwareGLContext::SoftwareGLContext(Gfx::Bitmap& frontbuffer) - : m_frontbuffer(frontbuffer) + : m_viewport(frontbuffer.rect()) + , m_frontbuffer(frontbuffer) , m_rasterizer(frontbuffer.size()) , m_device_info(m_rasterizer.info()) { @@ -159,6 +160,18 @@ Optional SoftwareGLContext::get_context_parameter(GLenum name) return ContextParameter { .type = GL_INT, .value = { .integer_value = 0 } }; case GL_UNPACK_SWAP_BYTES: return ContextParameter { .type = GL_BOOL, .value = { .boolean_value = false } }; + case GL_VIEWPORT: + return ContextParameter { + .type = GL_INT, + .count = 4, + .value = { + .integer_list = { + m_viewport.x(), + m_viewport.y(), + m_viewport.width(), + m_viewport.height(), + } } + }; default: dbgln_if(GL_DEBUG, "get_context_parameter({:#x}): unknown context parameter", name); return {}; @@ -577,11 +590,13 @@ void SoftwareGLContext::gl_viewport(GLint x, GLint y, GLsizei width, GLsizei hei APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_viewport, x, y, width, height); RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION); + RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); - (void)(x); - (void)(y); - (void)(width); - (void)(height); + m_viewport = { x, y, width, height }; + + auto rasterizer_options = m_rasterizer.options(); + rasterizer_options.viewport = m_viewport; + m_rasterizer.set_options(rasterizer_options); } void SoftwareGLContext::gl_enable(GLenum capability) diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.h b/Userland/Libraries/LibGL/SoftwareGLContext.h index e685710004..a02bd9fd12 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.h +++ b/Userland/Libraries/LibGL/SoftwareGLContext.h @@ -179,6 +179,8 @@ private: // FIXME: implement multi-texturing: the texture matrix stack should live inside a texture unit Vector m_texture_matrix_stack; + Gfx::IntRect m_viewport; + FloatVector4 m_clear_color { 0.0f, 0.0f, 0.0f, 0.0f }; double m_clear_depth { 1.0 }; GLint m_clear_stencil { 0 }; diff --git a/Userland/Libraries/LibSoftGPU/Device.cpp b/Userland/Libraries/LibSoftGPU/Device.cpp index 4b596f1e26..ef64a5526f 100644 --- a/Userland/Libraries/LibSoftGPU/Device.cpp +++ b/Userland/Libraries/LibSoftGPU/Device.cpp @@ -468,6 +468,7 @@ Device::Device(const Gfx::IntSize& size) , m_depth_buffer { adopt_own(*new DepthBuffer(size)) } { m_options.scissor_box = m_render_target->rect(); + m_options.viewport = m_render_target->rect(); } DeviceInfo Device::info() const @@ -561,9 +562,6 @@ void Device::draw_primitives(PrimitiveType primitive_type, FloatMatrix4x4 const& m_enabled_texture_units = enabled_texture_units; - float scr_width = m_render_target->width(); - float scr_height = m_render_target->height(); - m_triangle_list.clear_with_capacity(); m_processed_triangles.clear_with_capacity(); @@ -621,6 +619,11 @@ void Device::draw_primitives(PrimitiveType primitive_type, FloatMatrix4x4 const& } // Now let's transform each triangle and send that to the GPU + auto const viewport = window_coordinates_to_target_coordinates(m_options.viewport, m_render_target->rect()); + auto const viewport_half_width = viewport.width() / 2.0f; + auto const viewport_half_height = viewport.height() / 2.0f; + auto const viewport_center_x = viewport.x() + viewport_half_width; + auto const viewport_center_y = viewport.y() + viewport_half_height; auto const depth_half_range = (m_options.depth_max - m_options.depth_min) / 2; auto const depth_halfway = (m_options.depth_min + m_options.depth_max) / 2; for (auto& triangle : m_triangle_list) { @@ -663,12 +666,11 @@ void Device::draw_primitives(PrimitiveType primitive_type, FloatMatrix4x4 const& one_over_w, }; - // To window coordinates - // FIXME: implement viewport functionality + // To window coordinates - note that we flip the Y coordinate into target space vec.window_coordinates = { - scr_width / 2 + ndc_coordinates.x() * scr_width / 2, - scr_height / 2 - ndc_coordinates.y() * scr_height / 2, - depth_half_range * ndc_coordinates.z() + depth_halfway, + viewport_center_x + ndc_coordinates.x() * viewport_half_width, + viewport_center_y - ndc_coordinates.y() * viewport_half_height, + depth_halfway + ndc_coordinates.z() * depth_half_range, ndc_coordinates.w(), }; } diff --git a/Userland/Libraries/LibSoftGPU/Device.h b/Userland/Libraries/LibSoftGPU/Device.h index dbd32b3967..3b42bacdf6 100644 --- a/Userland/Libraries/LibSoftGPU/Device.h +++ b/Userland/Libraries/LibSoftGPU/Device.h @@ -66,6 +66,7 @@ struct RasterizerOptions { bool cull_front { false }; u8 texcoord_generation_enabled_coordinates { TexCoordGenerationCoordinate::None }; Array texcoord_generation_config {}; + Gfx::IntRect viewport; }; struct PixelQuad;