mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:27:35 +00:00
LibGL: Implement glScissor()
This commit is contained in:
parent
6dd2ebfe8e
commit
bb58f6ccab
9 changed files with 83 additions and 10 deletions
|
@ -33,4 +33,12 @@ void DepthBuffer::clear(float depth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DepthBuffer::clear(Gfx::IntRect bounds, float depth)
|
||||||
|
{
|
||||||
|
bounds.intersect({ 0, 0, m_size.width(), m_size.height() });
|
||||||
|
for (int y = bounds.top(); y <= bounds.bottom(); ++y)
|
||||||
|
for (int x = bounds.left(); x <= bounds.right(); ++x)
|
||||||
|
m_data[y * m_size.width() + x] = depth;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibGfx/Size.h>
|
#include <LibGfx/Size.h>
|
||||||
|
|
||||||
namespace GL {
|
namespace GL {
|
||||||
|
@ -18,6 +19,7 @@ public:
|
||||||
float* scanline(int y);
|
float* scanline(int y);
|
||||||
|
|
||||||
void clear(float depth);
|
void clear(float depth);
|
||||||
|
void clear(Gfx::IntRect bounds, float depth);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Gfx::IntSize m_size;
|
Gfx::IntSize m_size;
|
||||||
|
|
|
@ -290,6 +290,10 @@ extern "C" {
|
||||||
#define GL_FOG_COLOR 0x0B66
|
#define GL_FOG_COLOR 0x0B66
|
||||||
#define GL_FOG_DENSITY 0x0B62
|
#define GL_FOG_DENSITY 0x0B62
|
||||||
|
|
||||||
|
// Scissor enums
|
||||||
|
#define GL_SCISSOR_BOX 0x0C10
|
||||||
|
#define GL_SCISSOR_TEST 0x0C11
|
||||||
|
|
||||||
// OpenGL State & GLGet
|
// OpenGL State & GLGet
|
||||||
#define GL_MODELVIEW_MATRIX 0x0BA6
|
#define GL_MODELVIEW_MATRIX 0x0BA6
|
||||||
|
|
||||||
|
@ -416,6 +420,7 @@ GLAPI void glFogfv(GLenum mode, GLfloat* params);
|
||||||
GLAPI void glFogf(GLenum pname, GLfloat param);
|
GLAPI void glFogf(GLenum pname, GLfloat param);
|
||||||
GLAPI void glFogi(GLenum pname, GLint param);
|
GLAPI void glFogi(GLenum pname, GLint param);
|
||||||
GLAPI void glPixelStorei(GLenum pname, GLint param);
|
GLAPI void glPixelStorei(GLenum pname, GLint param);
|
||||||
|
GLAPI void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ public:
|
||||||
virtual void gl_fogf(GLenum pname, GLfloat params) = 0;
|
virtual void gl_fogf(GLenum pname, GLfloat params) = 0;
|
||||||
virtual void gl_fogi(GLenum pname, GLint param) = 0;
|
virtual void gl_fogi(GLenum pname, GLint param) = 0;
|
||||||
virtual void gl_pixel_store(GLenum pname, GLfloat param) = 0;
|
virtual void gl_pixel_store(GLenum pname, GLfloat param) = 0;
|
||||||
|
virtual void gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height) = 0;
|
||||||
|
|
||||||
virtual void present() = 0;
|
virtual void present() = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -154,3 +154,8 @@ void glPixelStorei(GLenum pname, GLint param)
|
||||||
{
|
{
|
||||||
g_gl_context->gl_pixel_store(pname, param);
|
g_gl_context->gl_pixel_store(pname, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
|
||||||
|
{
|
||||||
|
g_gl_context->gl_scissor(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
|
@ -549,6 +549,10 @@ void SoftwareGLContext::gl_enable(GLenum capability)
|
||||||
rasterizer_options.fog_enabled = true;
|
rasterizer_options.fog_enabled = true;
|
||||||
update_rasterizer_options = true;
|
update_rasterizer_options = true;
|
||||||
break;
|
break;
|
||||||
|
case GL_SCISSOR_TEST:
|
||||||
|
rasterizer_options.scissor_enabled = true;
|
||||||
|
update_rasterizer_options = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
||||||
}
|
}
|
||||||
|
@ -589,6 +593,10 @@ void SoftwareGLContext::gl_disable(GLenum capability)
|
||||||
rasterizer_options.fog_enabled = false;
|
rasterizer_options.fog_enabled = false;
|
||||||
update_rasterizer_options = true;
|
update_rasterizer_options = true;
|
||||||
break;
|
break;
|
||||||
|
case GL_SCISSOR_TEST:
|
||||||
|
rasterizer_options.scissor_enabled = false;
|
||||||
|
update_rasterizer_options = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM);
|
||||||
}
|
}
|
||||||
|
@ -614,6 +622,8 @@ GLboolean SoftwareGLContext::gl_is_enabled(GLenum capability)
|
||||||
return m_alpha_test_enabled;
|
return m_alpha_test_enabled;
|
||||||
case GL_FOG:
|
case GL_FOG:
|
||||||
return rasterizer_options.fog_enabled;
|
return rasterizer_options.fog_enabled;
|
||||||
|
case GL_SCISSOR_TEST:
|
||||||
|
return rasterizer_options.scissor_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_VALUE_WITH_ERROR_IF(true, GL_INVALID_ENUM, 0);
|
RETURN_VALUE_WITH_ERROR_IF(true, GL_INVALID_ENUM, 0);
|
||||||
|
@ -1472,6 +1482,14 @@ void SoftwareGLContext::gl_get_integerv(GLenum pname, GLint* data)
|
||||||
case GL_MAX_TEXTURE_SIZE:
|
case GL_MAX_TEXTURE_SIZE:
|
||||||
*data = 4096;
|
*data = 4096;
|
||||||
break;
|
break;
|
||||||
|
case GL_SCISSOR_BOX: {
|
||||||
|
auto scissor_box = m_rasterizer.options().scissor_box;
|
||||||
|
*(data + 0) = scissor_box.x();
|
||||||
|
*(data + 1) = scissor_box.y();
|
||||||
|
*(data + 2) = scissor_box.width();
|
||||||
|
*(data + 3) = scissor_box.height();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// According to the Khronos docs, we always return GL_INVALID_ENUM if we encounter a non-accepted value
|
// According to the Khronos docs, we always return GL_INVALID_ENUM if we encounter a non-accepted value
|
||||||
// for `pname`
|
// for `pname`
|
||||||
|
@ -1966,6 +1984,16 @@ void SoftwareGLContext::gl_pixel_store(GLenum pname, GLfloat param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoftwareGLContext::gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height)
|
||||||
|
{
|
||||||
|
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scissor, x, y, width, height);
|
||||||
|
RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE);
|
||||||
|
|
||||||
|
auto options = m_rasterizer.options();
|
||||||
|
options.scissor_box = { x, y, width, height };
|
||||||
|
m_rasterizer.set_options(options);
|
||||||
|
}
|
||||||
|
|
||||||
void SoftwareGLContext::present()
|
void SoftwareGLContext::present()
|
||||||
{
|
{
|
||||||
m_rasterizer.blit_to(*m_frontbuffer);
|
m_rasterizer.blit_to(*m_frontbuffer);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
#include <LibGfx/Matrix4x4.h>
|
#include <LibGfx/Matrix4x4.h>
|
||||||
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibGfx/Vector3.h>
|
#include <LibGfx/Vector3.h>
|
||||||
|
|
||||||
namespace GL {
|
namespace GL {
|
||||||
|
@ -96,6 +97,7 @@ public:
|
||||||
virtual void gl_fogf(GLenum pname, GLfloat param) override;
|
virtual void gl_fogf(GLenum pname, GLfloat param) override;
|
||||||
virtual void gl_fogi(GLenum pname, GLint param) override;
|
virtual void gl_fogi(GLenum pname, GLint param) override;
|
||||||
virtual void gl_pixel_store(GLenum pname, GLfloat param) override;
|
virtual void gl_pixel_store(GLenum pname, GLfloat param) override;
|
||||||
|
virtual void gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||||
virtual void present() override;
|
virtual void present() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -231,7 +233,8 @@ private:
|
||||||
decltype(&SoftwareGLContext::gl_draw_arrays),
|
decltype(&SoftwareGLContext::gl_draw_arrays),
|
||||||
decltype(&SoftwareGLContext::gl_draw_elements),
|
decltype(&SoftwareGLContext::gl_draw_elements),
|
||||||
decltype(&SoftwareGLContext::gl_depth_range),
|
decltype(&SoftwareGLContext::gl_depth_range),
|
||||||
decltype(&SoftwareGLContext::gl_polygon_offset)>;
|
decltype(&SoftwareGLContext::gl_polygon_offset),
|
||||||
|
decltype(&SoftwareGLContext::gl_scissor)>;
|
||||||
|
|
||||||
using ExtraSavedArguments = Variant<
|
using ExtraSavedArguments = Variant<
|
||||||
FloatMatrix4x4>;
|
FloatMatrix4x4>;
|
||||||
|
|
|
@ -183,11 +183,15 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate block-based bounds
|
// Calculate block-based bounds
|
||||||
|
auto render_bounds = render_target.rect();
|
||||||
|
if (options.scissor_enabled)
|
||||||
|
render_bounds.intersect(options.scissor_box);
|
||||||
|
int const block_padding = RASTERIZER_BLOCK_SIZE - 1;
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const int bx0 = max(0, min(min(v0.x(), v1.x()), v2.x()) ) / RASTERIZER_BLOCK_SIZE;
|
int const bx0 = max(render_bounds.left(), min(min(v0.x(), v1.x()), v2.x())) / RASTERIZER_BLOCK_SIZE;
|
||||||
const int bx1 = min(render_target.width(), max(max(v0.x(), v1.x()), v2.x()) + RASTERIZER_BLOCK_SIZE - 1) / RASTERIZER_BLOCK_SIZE;
|
int const bx1 = (min(render_bounds.right(), max(max(v0.x(), v1.x()), v2.x())) + block_padding) / RASTERIZER_BLOCK_SIZE;
|
||||||
const int by0 = max(0, min(min(v0.y(), v1.y()), v2.y()) ) / RASTERIZER_BLOCK_SIZE;
|
int const by0 = max(render_bounds.top(), min(min(v0.y(), v1.y()), v2.y())) / RASTERIZER_BLOCK_SIZE;
|
||||||
const int by1 = min(render_target.height(), max(max(v0.y(), v1.y()), v2.y()) + RASTERIZER_BLOCK_SIZE - 1) / RASTERIZER_BLOCK_SIZE;
|
int const by1 = (min(render_bounds.bottom(), max(max(v0.y(), v1.y()), v2.y())) + block_padding) / RASTERIZER_BLOCK_SIZE;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
static_assert(RASTERIZER_BLOCK_SIZE < sizeof(int) * 8, "RASTERIZER_BLOCK_SIZE must be smaller than the pixel_mask's width in bits");
|
static_assert(RASTERIZER_BLOCK_SIZE < sizeof(int) * 8, "RASTERIZER_BLOCK_SIZE must be smaller than the pixel_mask's width in bits");
|
||||||
|
@ -229,11 +233,10 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re
|
||||||
int y0 = by * RASTERIZER_BLOCK_SIZE;
|
int y0 = by * RASTERIZER_BLOCK_SIZE;
|
||||||
|
|
||||||
// Generate the coverage mask
|
// Generate the coverage mask
|
||||||
if (test_point(b0) && test_point(b1) && test_point(b2) && test_point(b3)) {
|
if (!options.scissor_enabled && test_point(b0) && test_point(b1) && test_point(b2) && test_point(b3)) {
|
||||||
// The block is fully contained within the triangle. Fill the mask with all 1s
|
// The block is fully contained within the triangle. Fill the mask with all 1s
|
||||||
for (int y = 0; y < RASTERIZER_BLOCK_SIZE; y++) {
|
for (int y = 0; y < RASTERIZER_BLOCK_SIZE; y++)
|
||||||
pixel_mask[y] = -1;
|
pixel_mask[y] = -1;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// The block overlaps at least one triangle edge.
|
// The block overlaps at least one triangle edge.
|
||||||
// We need to test coverage of every pixel within the block.
|
// We need to test coverage of every pixel within the block.
|
||||||
|
@ -242,7 +245,7 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re
|
||||||
pixel_mask[y] = 0;
|
pixel_mask[y] = 0;
|
||||||
|
|
||||||
for (int x = 0; x < RASTERIZER_BLOCK_SIZE; x++, coords += dbdx) {
|
for (int x = 0; x < RASTERIZER_BLOCK_SIZE; x++, coords += dbdx) {
|
||||||
if (test_point(coords))
|
if (test_point(coords) && (!options.scissor_enabled || render_bounds.contains(x0 + x, y0 + y)))
|
||||||
pixel_mask[y] |= 1 << x;
|
pixel_mask[y] |= 1 << x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,6 +484,7 @@ SoftwareRasterizer::SoftwareRasterizer(const Gfx::IntSize& min_size)
|
||||||
: m_render_target { Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, closest_multiple(min_size, RASTERIZER_BLOCK_SIZE)).release_value_but_fixme_should_propagate_errors() }
|
: m_render_target { Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, closest_multiple(min_size, RASTERIZER_BLOCK_SIZE)).release_value_but_fixme_should_propagate_errors() }
|
||||||
, m_depth_buffer { adopt_own(*new DepthBuffer(closest_multiple(min_size, RASTERIZER_BLOCK_SIZE))) }
|
, m_depth_buffer { adopt_own(*new DepthBuffer(closest_multiple(min_size, RASTERIZER_BLOCK_SIZE))) }
|
||||||
{
|
{
|
||||||
|
m_options.scissor_box = m_render_target->rect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareRasterizer::submit_triangle(const GLTriangle& triangle, const Array<TextureUnit, 32>& texture_units)
|
void SoftwareRasterizer::submit_triangle(const GLTriangle& triangle, const Array<TextureUnit, 32>& texture_units)
|
||||||
|
@ -559,14 +563,28 @@ void SoftwareRasterizer::clear_color(const FloatVector4& color)
|
||||||
uint8_t g = static_cast<uint8_t>(clamp(color.y(), 0.0f, 1.0f) * 255);
|
uint8_t g = static_cast<uint8_t>(clamp(color.y(), 0.0f, 1.0f) * 255);
|
||||||
uint8_t b = static_cast<uint8_t>(clamp(color.z(), 0.0f, 1.0f) * 255);
|
uint8_t b = static_cast<uint8_t>(clamp(color.z(), 0.0f, 1.0f) * 255);
|
||||||
uint8_t a = static_cast<uint8_t>(clamp(color.w(), 0.0f, 1.0f) * 255);
|
uint8_t a = static_cast<uint8_t>(clamp(color.w(), 0.0f, 1.0f) * 255);
|
||||||
|
auto const fill_color = Gfx::Color(r, g, b, a);
|
||||||
|
|
||||||
m_render_target->fill(Gfx::Color(r, g, b, a));
|
if (m_options.scissor_enabled) {
|
||||||
|
auto fill_rect = m_render_target->rect();
|
||||||
|
fill_rect.intersect(m_options.scissor_box);
|
||||||
|
Gfx::Painter painter { *m_render_target };
|
||||||
|
painter.fill_rect(fill_rect, fill_color);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_render_target->fill(fill_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareRasterizer::clear_depth(float depth)
|
void SoftwareRasterizer::clear_depth(float depth)
|
||||||
{
|
{
|
||||||
wait_for_all_threads();
|
wait_for_all_threads();
|
||||||
|
|
||||||
|
if (m_options.scissor_enabled) {
|
||||||
|
m_depth_buffer->clear(m_options.scissor_box, depth);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_depth_buffer->clear(depth);
|
m_depth_buffer->clear(depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <AK/Array.h>
|
#include <AK/Array.h>
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibGfx/Vector4.h>
|
#include <LibGfx/Vector4.h>
|
||||||
|
|
||||||
namespace GL {
|
namespace GL {
|
||||||
|
@ -44,6 +45,8 @@ struct RasterizerOptions {
|
||||||
GLboolean fog_enabled { false };
|
GLboolean fog_enabled { false };
|
||||||
GLfloat fog_start { 0.0f };
|
GLfloat fog_start { 0.0f };
|
||||||
GLfloat fog_end { 1.0f };
|
GLfloat fog_end { 1.0f };
|
||||||
|
bool scissor_enabled { false };
|
||||||
|
Gfx::IntRect scissor_box {};
|
||||||
GLenum draw_buffer { GL_BACK };
|
GLenum draw_buffer { GL_BACK };
|
||||||
GLfloat depth_offset_factor { 0 };
|
GLfloat depth_offset_factor { 0 };
|
||||||
GLfloat depth_offset_constant { 0 };
|
GLfloat depth_offset_constant { 0 };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue