summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJelle Raaijmakers <jelle@gmta.nl>2022-09-04 20:02:37 +0200
committerLinus Groh <mail@linusgroh.de>2022-09-11 22:37:07 +0100
commit44953a430159117fcfbbee6f3e47bfac89f5e215 (patch)
treec3b6220b0be8f5c41c173e3f306a1b4bf6887fdf
parentd7f1dc146e024ee947dd0941e37a40abb6cdae39 (diff)
downloadserenity-44953a430159117fcfbbee6f3e47bfac89f5e215.zip
LibGL+LibGPU+LibSoftGPU: Implement `glCopyTex(Sub)?Image2d`
These two methods copy from the frame buffer to (part of) a texture.
-rw-r--r--Userland/Libraries/LibGL/GLContext.cpp2
-rw-r--r--Userland/Libraries/LibGL/Image.cpp8
-rw-r--r--Userland/Libraries/LibGL/Texture.cpp87
-rw-r--r--Userland/Libraries/LibGPU/Device.h6
-rw-r--r--Userland/Libraries/LibSoftGPU/Device.cpp30
-rw-r--r--Userland/Libraries/LibSoftGPU/Device.h2
-rw-r--r--Userland/Libraries/LibSoftGPU/Image.h5
7 files changed, 118 insertions, 22 deletions
diff --git a/Userland/Libraries/LibGL/GLContext.cpp b/Userland/Libraries/LibGL/GLContext.cpp
index 23d2440604..da01df474c 100644
--- a/Userland/Libraries/LibGL/GLContext.cpp
+++ b/Userland/Libraries/LibGL/GLContext.cpp
@@ -496,6 +496,7 @@ void GLContext::gl_read_pixels(GLint x, GLint y, GLsizei width, GLsizei height,
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE);
+ RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
auto pixel_type_or_error = get_validated_pixel_type(GL_NONE, GL_NONE, format, type);
RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
@@ -561,6 +562,7 @@ void GLContext::gl_draw_pixels(GLsizei width, GLsizei height, GLenum format, GLe
// target and data is not evenly divisible into the number of bytes needed to store in memory a datum
// indicated by type.
+ RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
auto pixel_type_or_error = get_validated_pixel_type(GL_NONE, GL_NONE, format, type);
RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
diff --git a/Userland/Libraries/LibGL/Image.cpp b/Userland/Libraries/LibGL/Image.cpp
index d14c804779..98435c8686 100644
--- a/Userland/Libraries/LibGL/Image.cpp
+++ b/Userland/Libraries/LibGL/Image.cpp
@@ -95,10 +95,14 @@ ErrorOr<GPU::PixelType> get_validated_pixel_type(GLenum target, GLenum internal_
&& internal_format != GL_SRGB8_ALPHA8)
return Error::from_errno(GL_INVALID_ENUM);
- if ((format < GL_COLOR_INDEX || format > GL_LUMINANCE_ALPHA) && format != GL_BGR && format != GL_BGRA)
+ if (format != GL_NONE
+ && (format < GL_COLOR_INDEX || format > GL_LUMINANCE_ALPHA)
+ && format != GL_BGR
+ && format != GL_BGRA)
return Error::from_errno(GL_INVALID_ENUM);
- if (type != GL_BITMAP
+ if (type != GL_NONE
+ && type != GL_BITMAP
&& (type < GL_BYTE || type > GL_FLOAT)
&& type != GL_HALF_FLOAT
&& (type < GL_UNSIGNED_BYTE_3_3_2 || type > GL_UNSIGNED_INT_10_10_10_2)
diff --git a/Userland/Libraries/LibGL/Texture.cpp b/Userland/Libraries/LibGL/Texture.cpp
index 921bbfa7d7..b0da6554d3 100644
--- a/Userland/Libraries/LibGL/Texture.cpp
+++ b/Userland/Libraries/LibGL/Texture.cpp
@@ -82,21 +82,82 @@ void GLContext::gl_copy_tex_image_2d(GLenum target, GLint level, GLenum internal
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_copy_tex_image_2d, target, level, internalformat, x, y, width, height, border);
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
- // FIXME: implement
- dbgln_if(GL_DEBUG, "GLContext FIXME: implement gl_copy_tex_image_2d({:#x}, {}, {:#x}, {}, {}, {}, {}, {})",
- target, level, internalformat, x, y, width, height, border);
+ RETURN_WITH_ERROR_IF(internalformat == GL_NONE, GL_INVALID_ENUM);
+ auto pixel_type_or_error = get_validated_pixel_type(target, internalformat, GL_NONE, GL_NONE);
+ RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
+
+ RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
+ RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + Texture2D::MAX_TEXTURE_SIZE) || height > (2 + Texture2D::MAX_TEXTURE_SIZE), GL_INVALID_VALUE);
+ if (!m_device_info.supports_npot_textures)
+ RETURN_WITH_ERROR_IF(!is_power_of_two(width) || !is_power_of_two(height), GL_INVALID_VALUE);
+ RETURN_WITH_ERROR_IF(border != 0, GL_INVALID_VALUE);
+
+ auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
+ VERIFY(!texture_2d.is_null());
+
+ auto internal_pixel_format = pixel_format_for_internal_format(internalformat);
+ if (level == 0) {
+ texture_2d->set_device_image(m_rasterizer->create_image(internal_pixel_format, width, height, 1, 999, 1));
+ m_sampler_config_is_dirty = true;
+ }
+
+ auto pixel_type = pixel_type_or_error.release_value();
+ if (pixel_type.format == GPU::PixelFormat::DepthComponent) {
+ m_rasterizer->blit_from_depth_buffer(
+ *texture_2d->device_image(),
+ level,
+ { static_cast<u32>(width), static_cast<u32>(height) },
+ { x, y },
+ { 0, 0, 0 });
+ } else if (pixel_type.format == GPU::PixelFormat::StencilIndex) {
+ dbgln("{}: GL_STENCIL_INDEX is not yet supported", __FUNCTION__);
+ } else {
+ m_rasterizer->blit_from_color_buffer(
+ *texture_2d->device_image(),
+ level,
+ { static_cast<u32>(width), static_cast<u32>(height) },
+ { x, y },
+ { 0, 0, 0 });
+ }
}
void GLContext::gl_copy_tex_sub_image_2d(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
{
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_copy_tex_sub_image_2d, target, level, xoffset, yoffset, x, y, width, height);
- RETURN_WITH_ERROR_IF(!(target == GL_TEXTURE_2D || target == GL_TEXTURE_1D_ARRAY), GL_INVALID_ENUM);
- RETURN_WITH_ERROR_IF(level < 0, GL_INVALID_VALUE);
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
- // FIXME: implement
- dbgln_if(GL_DEBUG, "GLContext FIXME: implement gl_copy_tex_sub_image_2d({:#x}, {}, {}, {}, {}, {}, {}, {})",
- target, level, xoffset, yoffset, x, y, width, height);
+ RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
+ RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + Texture2D::MAX_TEXTURE_SIZE) || height > (2 + Texture2D::MAX_TEXTURE_SIZE), GL_INVALID_VALUE);
+
+ auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
+ VERIFY(!texture_2d.is_null());
+ RETURN_WITH_ERROR_IF(texture_2d->device_image().is_null(), GL_INVALID_OPERATION);
+
+ m_rasterizer->blit_from_color_buffer(
+ *texture_2d->device_image(),
+ level,
+ { static_cast<u32>(width), static_cast<u32>(height) },
+ { x, y },
+ { xoffset, yoffset, 0 });
+
+ // FIXME: use GPU::PixelFormat for Texture2D's internal format
+ if (texture_2d->internal_format() == GL_DEPTH_COMPONENT) {
+ m_rasterizer->blit_from_depth_buffer(
+ *texture_2d->device_image(),
+ level,
+ { static_cast<u32>(width), static_cast<u32>(height) },
+ { x, y },
+ { 0, 0, 0 });
+ } else if (texture_2d->internal_format() == GL_STENCIL_INDEX) {
+ dbgln("{}: GL_STENCIL_INDEX is not yet supported", __FUNCTION__);
+ } else {
+ m_rasterizer->blit_from_color_buffer(
+ *texture_2d->device_image(),
+ level,
+ { static_cast<u32>(width), static_cast<u32>(height) },
+ { x, y },
+ { 0, 0, 0 });
+ }
}
void GLContext::gl_delete_textures(GLsizei n, GLuint const* textures)
@@ -146,6 +207,7 @@ void GLContext::gl_gen_textures(GLsizei n, GLuint* textures)
void GLContext::gl_get_tex_image(GLenum target, GLint level, GLenum format, GLenum type, void* pixels)
{
RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
+ RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
auto pixel_type_or_error = get_validated_pixel_type(target, GL_NONE, format, type);
RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
@@ -467,16 +529,14 @@ void GLContext::gl_tex_image_2d(GLenum target, GLint level, GLint internal_forma
{
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
+ RETURN_WITH_ERROR_IF(internal_format == GL_NONE || format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
auto pixel_type_or_error = get_validated_pixel_type(target, internal_format, format, type);
RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
RETURN_WITH_ERROR_IF(level < 0 || level > Texture2D::LOG2_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
RETURN_WITH_ERROR_IF(width < 0 || height < 0 || width > (2 + Texture2D::MAX_TEXTURE_SIZE) || height > (2 + Texture2D::MAX_TEXTURE_SIZE), GL_INVALID_VALUE);
- // Check if width and height are a power of 2
- if (!m_device_info.supports_npot_textures) {
- RETURN_WITH_ERROR_IF(!is_power_of_two(width), GL_INVALID_VALUE);
- RETURN_WITH_ERROR_IF(!is_power_of_two(height), GL_INVALID_VALUE);
- }
+ if (!m_device_info.supports_npot_textures)
+ RETURN_WITH_ERROR_IF(!is_power_of_two(width) || !is_power_of_two(height), GL_INVALID_VALUE);
RETURN_WITH_ERROR_IF(border != 0, GL_INVALID_VALUE);
auto texture_2d = m_active_texture_unit->texture_2d_target_texture();
@@ -622,6 +682,7 @@ void GLContext::gl_tex_sub_image_2d(GLenum target, GLint level, GLint xoffset, G
VERIFY(!texture_2d.is_null());
RETURN_WITH_ERROR_IF(texture_2d->device_image().is_null(), GL_INVALID_OPERATION);
+ RETURN_WITH_ERROR_IF(format == GL_NONE || type == GL_NONE, GL_INVALID_ENUM);
auto pixel_type_or_error = get_validated_pixel_type(target, texture_2d->internal_format(), format, type);
RETURN_WITH_ERROR_IF(pixel_type_or_error.is_error(), pixel_type_or_error.release_error().code());
diff --git a/Userland/Libraries/LibGPU/Device.h b/Userland/Libraries/LibGPU/Device.h
index b40704e4c4..3c019b68e5 100644
--- a/Userland/Libraries/LibGPU/Device.h
+++ b/Userland/Libraries/LibGPU/Device.h
@@ -8,10 +8,7 @@
#pragma once
#include <AK/Array.h>
-#include <AK/Error.h>
#include <AK/NonnullRefPtr.h>
-#include <AK/RefCounted.h>
-#include <AK/RefPtr.h>
#include <AK/Vector.h>
#include <LibGPU/DeviceInfo.h>
#include <LibGPU/Enums.h>
@@ -29,7 +26,6 @@
#include <LibGfx/Bitmap.h>
#include <LibGfx/Matrix3x3.h>
#include <LibGfx/Matrix4x4.h>
-#include <LibGfx/Rect.h>
#include <LibGfx/Size.h>
#include <LibGfx/Vector2.h>
#include <LibGfx/Vector4.h>
@@ -48,8 +44,10 @@ public:
virtual void clear_depth(DepthType) = 0;
virtual void clear_stencil(StencilType) = 0;
virtual void blit_from_color_buffer(Gfx::Bitmap& target) = 0;
+ virtual void blit_from_color_buffer(NonnullRefPtr<Image>, u32 level, Vector2<u32> input_size, Vector2<i32> input_offset, Vector3<i32> output_offset) = 0;
virtual void blit_from_color_buffer(void*, Vector2<i32> offset, GPU::ImageDataLayout const&) = 0;
virtual void blit_from_depth_buffer(void*, Vector2<i32> offset, GPU::ImageDataLayout const&) = 0;
+ virtual void blit_from_depth_buffer(NonnullRefPtr<Image>, u32 level, Vector2<u32> input_size, Vector2<i32> input_offset, Vector3<i32> output_offset) = 0;
virtual void blit_to_color_buffer_at_raster_position(void const*, GPU::ImageDataLayout const&) = 0;
virtual void blit_to_depth_buffer_at_raster_position(void const*, GPU::ImageDataLayout const&) = 0;
virtual void set_options(RasterizerOptions const&) = 0;
diff --git a/Userland/Libraries/LibSoftGPU/Device.cpp b/Userland/Libraries/LibSoftGPU/Device.cpp
index ac3870780a..0033ba6d87 100644
--- a/Userland/Libraries/LibSoftGPU/Device.cpp
+++ b/Userland/Libraries/LibSoftGPU/Device.cpp
@@ -1466,6 +1466,21 @@ void Device::blit_from_color_buffer(Gfx::Bitmap& target)
draw_statistics_overlay(target);
}
+void Device::blit_from_color_buffer(NonnullRefPtr<GPU::Image> image, u32 level, Vector2<u32> input_size, Vector2<i32> input_offset, Vector3<i32> output_offset)
+{
+ auto input_layout = color_buffer_data_layout(input_size, input_offset);
+ auto const* input_data = m_frame_buffer->color_buffer()->scanline(0);
+
+ auto const& softgpu_image = reinterpret_cast<Image*>(image.ptr());
+ auto output_layout = softgpu_image->image_data_layout(level, output_offset);
+ auto* output_data = softgpu_image->texel_pointer(0, level, 0, 0, 0);
+
+ PixelConverter converter { input_layout, output_layout };
+ auto conversion_result = converter.convert(input_data, output_data, {});
+ if (conversion_result.is_error())
+ dbgln("Pixel conversion failed: {}", conversion_result.error().string_literal());
+}
+
void Device::blit_from_color_buffer(void* output_data, Vector2<i32> input_offset, GPU::ImageDataLayout const& output_layout)
{
auto const& output_selection = output_layout.selection;
@@ -1490,6 +1505,21 @@ void Device::blit_from_depth_buffer(void* output_data, Vector2<i32> input_offset
dbgln("Pixel conversion failed: {}", conversion_result.error().string_literal());
}
+void Device::blit_from_depth_buffer(NonnullRefPtr<GPU::Image> image, u32 level, Vector2<u32> input_size, Vector2<i32> input_offset, Vector3<i32> output_offset)
+{
+ auto input_layout = depth_buffer_data_layout(input_size, input_offset);
+ auto const* input_data = m_frame_buffer->depth_buffer()->scanline(0);
+
+ auto const& softgpu_image = reinterpret_cast<Image*>(image.ptr());
+ auto output_layout = softgpu_image->image_data_layout(level, output_offset);
+ auto* output_data = softgpu_image->texel_pointer(0, level, 0, 0, 0);
+
+ PixelConverter converter { input_layout, output_layout };
+ auto conversion_result = converter.convert(input_data, output_data, {});
+ if (conversion_result.is_error())
+ dbgln("Pixel conversion failed: {}", conversion_result.error().string_literal());
+}
+
void Device::blit_to_color_buffer_at_raster_position(void const* input_data, GPU::ImageDataLayout const& input_layout)
{
if (!m_raster_position.valid)
diff --git a/Userland/Libraries/LibSoftGPU/Device.h b/Userland/Libraries/LibSoftGPU/Device.h
index 7fa1dbfbfd..c0b839d008 100644
--- a/Userland/Libraries/LibSoftGPU/Device.h
+++ b/Userland/Libraries/LibSoftGPU/Device.h
@@ -53,8 +53,10 @@ public:
virtual void clear_depth(GPU::DepthType) override;
virtual void clear_stencil(GPU::StencilType) override;
virtual void blit_from_color_buffer(Gfx::Bitmap& target) override;
+ virtual void blit_from_color_buffer(NonnullRefPtr<GPU::Image>, u32 level, Vector2<u32> input_size, Vector2<i32> input_offset, Vector3<i32> output_offset) override;
virtual void blit_from_color_buffer(void*, Vector2<i32> offset, GPU::ImageDataLayout const&) override;
virtual void blit_from_depth_buffer(void*, Vector2<i32> offset, GPU::ImageDataLayout const&) override;
+ virtual void blit_from_depth_buffer(NonnullRefPtr<GPU::Image>, u32 level, Vector2<u32> input_size, Vector2<i32> input_offset, Vector3<i32> output_offset) override;
virtual void blit_to_color_buffer_at_raster_position(void const*, GPU::ImageDataLayout const&) override;
virtual void blit_to_depth_buffer_at_raster_position(void const*, GPU::ImageDataLayout const&) override;
virtual void set_options(GPU::RasterizerOptions const&) override;
diff --git a/Userland/Libraries/LibSoftGPU/Image.h b/Userland/Libraries/LibSoftGPU/Image.h
index 4ccfc3cbd4..6f92cc3ce5 100644
--- a/Userland/Libraries/LibSoftGPU/Image.h
+++ b/Userland/Libraries/LibSoftGPU/Image.h
@@ -31,6 +31,8 @@ public:
bool height_is_power_of_two() const { return m_height_is_power_of_two; }
bool depth_is_power_of_two() const { return m_depth_is_power_of_two; }
+ GPU::ImageDataLayout image_data_layout(u32 level, Vector3<i32> offset) const;
+
FloatVector4 texel(u32 layer, u32 level, int x, int y, int z) const
{
return *texel_pointer(layer, level, x, y, z);
@@ -45,9 +47,6 @@ public:
virtual void read_texels(u32 layer, u32 level, Vector3<i32> const& input_offset, void* output_data, GPU::ImageDataLayout const&) const override;
virtual void copy_texels(GPU::Image const& source, u32 source_layer, u32 source_level, Vector3<u32> const& source_offset, Vector3<u32> const& size, u32 destination_layer, u32 destination_level, Vector3<u32> const& destination_offset) override;
-private:
- GPU::ImageDataLayout image_data_layout(u32 level, Vector3<i32> offset) const;
-
FloatVector4 const* texel_pointer(u32 layer, u32 level, int x, int y, int z) const
{
return m_mipmap_buffers[layer * m_num_layers + level]->buffer_pointer(x, y, z);