mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 03:32:55 +00:00
gl: Refactor image and command-context handling
- Move texture object code out of the monolithic header - All texture binds go through the shared state - Transient texture binds use a dedicated temp image slot shared with native UI
This commit is contained in:
parent
0e5514003a
commit
d577cebd89
@ -455,6 +455,8 @@ target_sources(rpcs3_emu PRIVATE
|
||||
RSX/Capture/rsx_capture.cpp
|
||||
RSX/Capture/rsx_replay.cpp
|
||||
RSX/GL/glutils/buffer_object.cpp
|
||||
RSX/GL/glutils/common.cpp
|
||||
RSX/GL/glutils/image.cpp
|
||||
RSX/GL/glutils/ring_buffer.cpp
|
||||
RSX/GL/GLCommonDecompiler.cpp
|
||||
RSX/GL/GLCompute.cpp
|
||||
|
@ -96,6 +96,7 @@ void GLGSRender::on_init_thread()
|
||||
m_occlusion_type = g_cfg.video.precise_zpass_count ? GL_SAMPLES_PASSED : GL_ANY_SAMPLES_PASSED;
|
||||
|
||||
gl::init();
|
||||
gl::set_command_context(gl_state);
|
||||
|
||||
//Enable adaptive vsync if vsync is requested
|
||||
gl::set_swapinterval(g_cfg.video.vsync ? -1 : 0);
|
||||
|
@ -14,18 +14,6 @@ namespace gl
|
||||
capabilities g_driver_caps;
|
||||
const fbo screen{};
|
||||
|
||||
static thread_local bool s_tls_primary_context_thread = false;
|
||||
|
||||
void set_primary_context_thread(bool value)
|
||||
{
|
||||
s_tls_primary_context_thread = value;
|
||||
}
|
||||
|
||||
bool is_primary_context_thread()
|
||||
{
|
||||
return s_tls_primary_context_thread;
|
||||
}
|
||||
|
||||
void flush_command_queue(fence& fence_obj)
|
||||
{
|
||||
fence_obj.check_signaled();
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "GLExecutionState.h"
|
||||
#include "../GCM.h"
|
||||
#include "../Common/TextureUtils.h"
|
||||
#include "../Program/GLSLTypes.h"
|
||||
@ -22,33 +21,15 @@
|
||||
#include "glutils/common.h"
|
||||
// TODO: Include on use
|
||||
#include "glutils/buffer_object.h"
|
||||
|
||||
#define GL_FRAGMENT_TEXTURES_START 0
|
||||
#define GL_VERTEX_TEXTURES_START (GL_FRAGMENT_TEXTURES_START + 16)
|
||||
#define GL_STENCIL_MIRRORS_START (GL_VERTEX_TEXTURES_START + 4)
|
||||
#define GL_STREAM_BUFFER_START (GL_STENCIL_MIRRORS_START + 16)
|
||||
|
||||
#define UBO_SLOT(x) (x)
|
||||
#define SSBO_SLOT(x) (x)
|
||||
|
||||
#define GL_VERTEX_PARAMS_BIND_SLOT UBO_SLOT(0)
|
||||
#define GL_VERTEX_LAYOUT_BIND_SLOT UBO_SLOT(1)
|
||||
#define GL_VERTEX_CONSTANT_BUFFERS_BIND_SLOT UBO_SLOT(2)
|
||||
#define GL_FRAGMENT_CONSTANT_BUFFERS_BIND_SLOT UBO_SLOT(3)
|
||||
#define GL_FRAGMENT_STATE_BIND_SLOT UBO_SLOT(4)
|
||||
#define GL_FRAGMENT_TEXTURE_PARAMS_BIND_SLOT UBO_SLOT(5)
|
||||
#define GL_RASTERIZER_STATE_BIND_SLOT UBO_SLOT(6)
|
||||
#define GL_INTERPRETER_VERTEX_BLOCK SSBO_SLOT(0)
|
||||
#define GL_INTERPRETER_FRAGMENT_BLOCK SSBO_SLOT(1)
|
||||
#define GL_COMPUTE_BUFFER_SLOT(index) SSBO_SLOT(2 + index)
|
||||
#include "glutils/image.h"
|
||||
#include "glutils/pixel_settings.hpp"
|
||||
#include "glutils/state_tracker.hpp"
|
||||
|
||||
// Noop keyword outside of Windows (used in log_debug)
|
||||
#if !defined(_WIN32) && !defined(APIENTRY)
|
||||
#define APIENTRY
|
||||
#endif
|
||||
|
||||
//using enum rsx::format_class;
|
||||
using namespace ::rsx::format_class_;
|
||||
|
||||
namespace gl
|
||||
{
|
||||
@ -56,13 +37,8 @@ namespace gl
|
||||
bool is_primitive_native(rsx::primitive_type in);
|
||||
GLenum draw_mode(rsx::primitive_type in);
|
||||
|
||||
void set_primary_context_thread(bool = true);
|
||||
bool is_primary_context_thread();
|
||||
void flush_command_queue(fence& fence_obj);
|
||||
|
||||
// Texture helpers
|
||||
std::array<GLenum, 4> apply_swizzle_remap(const std::array<GLenum, 4>& swizzle_remap, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& decoded_remap);
|
||||
|
||||
class exception : public std::exception
|
||||
{
|
||||
protected:
|
||||
@ -127,157 +103,6 @@ namespace gl
|
||||
depth_stencil = depth | stencil
|
||||
};
|
||||
|
||||
class pixel_pack_settings
|
||||
{
|
||||
bool m_swap_bytes = false;
|
||||
bool m_lsb_first = false;
|
||||
int m_row_length = 0;
|
||||
int m_image_height = 0;
|
||||
int m_skip_rows = 0;
|
||||
int m_skip_pixels = 0;
|
||||
int m_skip_images = 0;
|
||||
int m_alignment = 4;
|
||||
|
||||
public:
|
||||
void apply() const
|
||||
{
|
||||
glPixelStorei(GL_PACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE);
|
||||
glPixelStorei(GL_PACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, m_row_length);
|
||||
glPixelStorei(GL_PACK_IMAGE_HEIGHT, m_image_height);
|
||||
glPixelStorei(GL_PACK_SKIP_ROWS, m_skip_rows);
|
||||
glPixelStorei(GL_PACK_SKIP_PIXELS, m_skip_pixels);
|
||||
glPixelStorei(GL_PACK_SKIP_IMAGES, m_skip_images);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, m_alignment);
|
||||
}
|
||||
|
||||
pixel_pack_settings& swap_bytes(bool value = true)
|
||||
{
|
||||
m_swap_bytes = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& lsb_first(bool value = true)
|
||||
{
|
||||
m_lsb_first = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& row_length(int value)
|
||||
{
|
||||
m_row_length = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& image_height(int value)
|
||||
{
|
||||
m_image_height = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& skip_rows(int value)
|
||||
{
|
||||
m_skip_rows = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& skip_pixels(int value)
|
||||
{
|
||||
m_skip_pixels = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& skip_images(int value)
|
||||
{
|
||||
m_skip_images = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& alignment(int value)
|
||||
{
|
||||
m_alignment = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool get_swap_bytes() const
|
||||
{
|
||||
return m_swap_bytes;
|
||||
}
|
||||
int get_row_length() const
|
||||
{
|
||||
return m_row_length;
|
||||
}
|
||||
};
|
||||
|
||||
class pixel_unpack_settings
|
||||
{
|
||||
bool m_swap_bytes = false;
|
||||
bool m_lsb_first = false;
|
||||
int m_row_length = 0;
|
||||
int m_image_height = 0;
|
||||
int m_skip_rows = 0;
|
||||
int m_skip_pixels = 0;
|
||||
int m_skip_images = 0;
|
||||
int m_alignment = 4;
|
||||
|
||||
public:
|
||||
void apply() const
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE);
|
||||
glPixelStorei(GL_UNPACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, m_row_length);
|
||||
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_image_height);
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, m_skip_rows);
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_skip_pixels);
|
||||
glPixelStorei(GL_UNPACK_SKIP_IMAGES, m_skip_images);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment);
|
||||
}
|
||||
|
||||
pixel_unpack_settings& swap_bytes(bool value = true)
|
||||
{
|
||||
m_swap_bytes = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& lsb_first(bool value = true)
|
||||
{
|
||||
m_lsb_first = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& row_length(int value)
|
||||
{
|
||||
m_row_length = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& image_height(int value)
|
||||
{
|
||||
m_image_height = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& skip_rows(int value)
|
||||
{
|
||||
m_skip_rows = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& skip_pixels(int value)
|
||||
{
|
||||
m_skip_pixels = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& skip_images(int value)
|
||||
{
|
||||
m_skip_images = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& alignment(int value)
|
||||
{
|
||||
m_alignment = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool get_swap_bytes() const
|
||||
{
|
||||
return m_swap_bytes;
|
||||
}
|
||||
|
||||
int get_row_length() const
|
||||
{
|
||||
return m_row_length;
|
||||
}
|
||||
};
|
||||
|
||||
class vao;
|
||||
class attrib_t;
|
||||
|
||||
@ -574,694 +399,6 @@ namespace gl
|
||||
}
|
||||
};
|
||||
|
||||
enum image_aspect : u32
|
||||
{
|
||||
color = 1,
|
||||
depth = 2,
|
||||
stencil = 4
|
||||
};
|
||||
|
||||
class texture
|
||||
{
|
||||
friend class texture_view;
|
||||
|
||||
public:
|
||||
enum class type
|
||||
{
|
||||
ubyte = GL_UNSIGNED_BYTE,
|
||||
ushort = GL_UNSIGNED_SHORT,
|
||||
uint = GL_UNSIGNED_INT,
|
||||
|
||||
ubyte_3_3_2 = GL_UNSIGNED_BYTE_3_3_2,
|
||||
ubyte_2_3_3_rev = GL_UNSIGNED_BYTE_2_3_3_REV,
|
||||
|
||||
ushort_5_6_5 = GL_UNSIGNED_SHORT_5_6_5,
|
||||
ushort_5_6_5_rev = GL_UNSIGNED_SHORT_5_6_5_REV,
|
||||
ushort_4_4_4_4 = GL_UNSIGNED_SHORT_4_4_4_4,
|
||||
ushort_4_4_4_4_rev = GL_UNSIGNED_SHORT_4_4_4_4_REV,
|
||||
ushort_5_5_5_1 = GL_UNSIGNED_SHORT_5_5_5_1,
|
||||
ushort_1_5_5_5_rev = GL_UNSIGNED_SHORT_1_5_5_5_REV,
|
||||
|
||||
uint_8_8_8_8 = GL_UNSIGNED_INT_8_8_8_8,
|
||||
uint_8_8_8_8_rev = GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
uint_10_10_10_2 = GL_UNSIGNED_INT_10_10_10_2,
|
||||
uint_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
uint_24_8 = GL_UNSIGNED_INT_24_8,
|
||||
float32_uint8 = GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
|
||||
|
||||
sbyte = GL_BYTE,
|
||||
sshort = GL_SHORT,
|
||||
sint = GL_INT,
|
||||
f16 = GL_HALF_FLOAT,
|
||||
f32 = GL_FLOAT,
|
||||
f64 = GL_DOUBLE,
|
||||
};
|
||||
|
||||
enum class channel
|
||||
{
|
||||
zero = GL_ZERO,
|
||||
one = GL_ONE,
|
||||
r = GL_RED,
|
||||
g = GL_GREEN,
|
||||
b = GL_BLUE,
|
||||
a = GL_ALPHA,
|
||||
};
|
||||
|
||||
enum class format
|
||||
{
|
||||
r = GL_RED,
|
||||
rg = GL_RG,
|
||||
rgb = GL_RGB,
|
||||
rgba = GL_RGBA,
|
||||
|
||||
bgr = GL_BGR,
|
||||
bgra = GL_BGRA,
|
||||
|
||||
stencil = GL_STENCIL_INDEX,
|
||||
depth = GL_DEPTH_COMPONENT,
|
||||
depth_stencil = GL_DEPTH_STENCIL
|
||||
};
|
||||
|
||||
enum class internal_format
|
||||
{
|
||||
stencil8 = GL_STENCIL_INDEX8,
|
||||
depth16 = GL_DEPTH_COMPONENT16,
|
||||
depth32f = GL_DEPTH_COMPONENT32F,
|
||||
depth24_stencil8 = GL_DEPTH24_STENCIL8,
|
||||
depth32f_stencil8 = GL_DEPTH32F_STENCIL8,
|
||||
|
||||
compressed_rgb_s3tc_dxt1 = GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
|
||||
compressed_rgba_s3tc_dxt1 = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
|
||||
compressed_rgba_s3tc_dxt3 = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
|
||||
compressed_rgba_s3tc_dxt5 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
|
||||
|
||||
//Sized internal formats, see opengl spec document on glTexImage2D, table 3
|
||||
rgba8 = GL_RGBA8,
|
||||
rgb565 = GL_RGB565,
|
||||
rgb5a1 = GL_RGB5_A1,
|
||||
rgba4 = GL_RGBA4,
|
||||
r8 = GL_R8,
|
||||
r16 = GL_R16,
|
||||
r32f = GL_R32F,
|
||||
rg8 = GL_RG8,
|
||||
rg16 = GL_RG16,
|
||||
rg16f = GL_RG16F,
|
||||
rgba16f = GL_RGBA16F,
|
||||
rgba32f = GL_RGBA32F
|
||||
};
|
||||
|
||||
enum class wrap
|
||||
{
|
||||
repeat = GL_REPEAT,
|
||||
mirrored_repeat = GL_MIRRORED_REPEAT,
|
||||
clamp_to_edge = GL_CLAMP_TO_EDGE,
|
||||
clamp_to_border = GL_CLAMP_TO_BORDER,
|
||||
mirror_clamp = GL_MIRROR_CLAMP_EXT,
|
||||
//mirror_clamp_to_edge = GL_MIRROR_CLAMP_TO_EDGE,
|
||||
mirror_clamp_to_border = GL_MIRROR_CLAMP_TO_BORDER_EXT
|
||||
};
|
||||
|
||||
enum class compare_mode
|
||||
{
|
||||
none = GL_NONE,
|
||||
ref_to_texture = GL_COMPARE_REF_TO_TEXTURE
|
||||
};
|
||||
|
||||
enum class target
|
||||
{
|
||||
texture1D = GL_TEXTURE_1D,
|
||||
texture2D = GL_TEXTURE_2D,
|
||||
texture3D = GL_TEXTURE_3D,
|
||||
textureCUBE = GL_TEXTURE_CUBE_MAP,
|
||||
textureBuffer = GL_TEXTURE_BUFFER
|
||||
};
|
||||
|
||||
protected:
|
||||
GLuint m_id = GL_NONE;
|
||||
GLuint m_width = 0;
|
||||
GLuint m_height = 0;
|
||||
GLuint m_depth = 0;
|
||||
GLuint m_mipmaps = 0;
|
||||
GLuint m_pitch = 0;
|
||||
GLuint m_compressed = GL_FALSE;
|
||||
GLuint m_aspect_flags = 0;
|
||||
|
||||
target m_target = target::texture2D;
|
||||
internal_format m_internal_format = internal_format::rgba8;
|
||||
std::array<GLenum, 4> m_component_layout;
|
||||
|
||||
rsx::format_class m_format_class = RSX_FORMAT_CLASS_UNDEFINED;
|
||||
|
||||
class save_binding_state
|
||||
{
|
||||
GLenum target = GL_NONE;
|
||||
GLuint old_binding = GL_NONE;
|
||||
|
||||
public:
|
||||
save_binding_state(GLenum target)
|
||||
{
|
||||
this->target = target;
|
||||
switch (target)
|
||||
{
|
||||
case GL_TEXTURE_1D:
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_1D, reinterpret_cast<GLint*>(&old_binding));
|
||||
break;
|
||||
case GL_TEXTURE_2D:
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast<GLint*>(&old_binding));
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_3D, reinterpret_cast<GLint*>(&old_binding));
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, reinterpret_cast<GLint*>(&old_binding));
|
||||
break;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D_ARRAY, reinterpret_cast<GLint*>(&old_binding));
|
||||
break;
|
||||
case GL_TEXTURE_BUFFER:
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_BUFFER, reinterpret_cast<GLint*>(&old_binding));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
~save_binding_state()
|
||||
{
|
||||
glBindTexture(target, old_binding);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
texture(const texture&) = delete;
|
||||
texture(texture&& texture_) = delete;
|
||||
|
||||
texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLenum sized_format,
|
||||
rsx::format_class format_class = rsx::RSX_FORMAT_CLASS_UNDEFINED)
|
||||
{
|
||||
save_binding_state save(target);
|
||||
glGenTextures(1, &m_id);
|
||||
glBindTexture(target, m_id); //Must bind to initialize the new texture
|
||||
|
||||
switch (target)
|
||||
{
|
||||
default:
|
||||
fmt::throw_exception("Invalid image target 0x%X", target);
|
||||
case GL_TEXTURE_1D:
|
||||
glTexStorage1D(target, mipmaps, sized_format, width);
|
||||
height = depth = 1;
|
||||
break;
|
||||
case GL_TEXTURE_2D:
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
glTexStorage2D(target, mipmaps, sized_format, width, height);
|
||||
depth = 1;
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
glTexStorage3D(target, mipmaps, sized_format, width, height, depth);
|
||||
break;
|
||||
case GL_TEXTURE_BUFFER:
|
||||
break;
|
||||
}
|
||||
|
||||
if (target != GL_TEXTURE_BUFFER)
|
||||
{
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
|
||||
glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
|
||||
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_depth = depth;
|
||||
m_mipmaps = mipmaps;
|
||||
m_aspect_flags = image_aspect::color;
|
||||
|
||||
switch (sized_format)
|
||||
{
|
||||
case GL_DEPTH_COMPONENT16:
|
||||
{
|
||||
m_pitch = width * 2;
|
||||
m_aspect_flags = image_aspect::depth;
|
||||
break;
|
||||
}
|
||||
case GL_DEPTH_COMPONENT32F:
|
||||
{
|
||||
m_pitch = width * 4;
|
||||
m_aspect_flags = image_aspect::depth;
|
||||
break;
|
||||
}
|
||||
case GL_DEPTH24_STENCIL8:
|
||||
case GL_DEPTH32F_STENCIL8:
|
||||
{
|
||||
m_pitch = width * 4;
|
||||
m_aspect_flags = image_aspect::depth | image_aspect::stencil;
|
||||
break;
|
||||
}
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
||||
{
|
||||
m_compressed = true;
|
||||
m_pitch = utils::align(width, 4) / 2;
|
||||
break;
|
||||
}
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
||||
{
|
||||
m_compressed = true;
|
||||
m_pitch = utils::align(width, 4);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
GLenum query_target = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
|
||||
GLint r, g, b, a;
|
||||
|
||||
glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_RED_SIZE, &r);
|
||||
glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_GREEN_SIZE, &g);
|
||||
glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_BLUE_SIZE, &b);
|
||||
glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_ALPHA_SIZE, &a);
|
||||
|
||||
m_pitch = width * (r + g + b + a) / 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_pitch)
|
||||
{
|
||||
fmt::throw_exception("Unhandled GL format 0x%X", sized_format);
|
||||
}
|
||||
|
||||
if (format_class == RSX_FORMAT_CLASS_UNDEFINED)
|
||||
{
|
||||
if (m_aspect_flags != image_aspect::color)
|
||||
{
|
||||
rsx_log.error("Undefined format class for depth texture is not allowed");
|
||||
}
|
||||
else
|
||||
{
|
||||
format_class = RSX_FORMAT_CLASS_COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_target = static_cast<texture::target>(target);
|
||||
m_internal_format = static_cast<internal_format>(sized_format);
|
||||
m_component_layout = { GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE };
|
||||
m_format_class = format_class;
|
||||
}
|
||||
|
||||
virtual ~texture()
|
||||
{
|
||||
if (m_id != GL_NONE)
|
||||
{
|
||||
glDeleteTextures(1, &m_id);
|
||||
m_id = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void set_native_component_layout(const std::array<GLenum, 4>& layout)
|
||||
{
|
||||
m_component_layout[0] = layout[0];
|
||||
m_component_layout[1] = layout[1];
|
||||
m_component_layout[2] = layout[2];
|
||||
m_component_layout[3] = layout[3];
|
||||
}
|
||||
|
||||
target get_target() const noexcept
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
static bool compressed_format(internal_format format_) noexcept
|
||||
{
|
||||
switch (format_)
|
||||
{
|
||||
case internal_format::compressed_rgb_s3tc_dxt1:
|
||||
case internal_format::compressed_rgba_s3tc_dxt1:
|
||||
case internal_format::compressed_rgba_s3tc_dxt3:
|
||||
case internal_format::compressed_rgba_s3tc_dxt5:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint id() const noexcept
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return (m_id != GL_NONE);
|
||||
}
|
||||
|
||||
GLuint width() const
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
GLuint height() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
GLuint depth() const
|
||||
{
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
GLuint levels() const
|
||||
{
|
||||
return m_mipmaps;
|
||||
}
|
||||
|
||||
GLuint pitch() const
|
||||
{
|
||||
return m_pitch;
|
||||
}
|
||||
|
||||
constexpr GLubyte samples() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
GLboolean compressed() const
|
||||
{
|
||||
return m_compressed;
|
||||
}
|
||||
|
||||
GLuint aspect() const
|
||||
{
|
||||
return m_aspect_flags;
|
||||
}
|
||||
|
||||
rsx::format_class format_class() const
|
||||
{
|
||||
return m_format_class;
|
||||
}
|
||||
|
||||
sizeu size2D() const
|
||||
{
|
||||
return{ m_width, m_height };
|
||||
}
|
||||
|
||||
size3u size3D() const
|
||||
{
|
||||
const auto depth = (m_target == target::textureCUBE) ? 6 : m_depth;
|
||||
return{ m_width, m_height, depth };
|
||||
}
|
||||
|
||||
texture::internal_format get_internal_format() const
|
||||
{
|
||||
return m_internal_format;
|
||||
}
|
||||
|
||||
std::array<GLenum, 4> get_native_component_layout() const
|
||||
{
|
||||
return m_component_layout;
|
||||
}
|
||||
|
||||
void copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
pixel_settings.apply();
|
||||
|
||||
switch (const auto target_ =static_cast<GLenum>(m_target))
|
||||
{
|
||||
case GL_TEXTURE_1D:
|
||||
{
|
||||
DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_2D:
|
||||
{
|
||||
DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_3D:
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
{
|
||||
DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
{
|
||||
if (get_driver_caps().ARB_dsa_supported)
|
||||
{
|
||||
glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
}
|
||||
else
|
||||
{
|
||||
rsx_log.warning("Cubemap upload via texture::copy_from is halfplemented!");
|
||||
auto ptr = static_cast<const u8*>(src);
|
||||
const auto end = std::min(6u, region.z + region.depth);
|
||||
for (unsigned face = region.z; face < end; ++face)
|
||||
{
|
||||
glTextureSubImage2DEXT(m_id, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), ptr);
|
||||
ptr += (region.width * region.height * 4); //TODO
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void copy_from(const void* src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
const coord3u region = { {}, size3D() };
|
||||
copy_from(src, format, type, 0, region, pixel_settings);
|
||||
}
|
||||
|
||||
void copy_from(buffer &buf, u32 gl_format_type, u32 offset, u32 length)
|
||||
{
|
||||
if (get_target() != target::textureBuffer)
|
||||
fmt::throw_exception("OpenGL error: texture cannot copy from buffer");
|
||||
|
||||
DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, gl_format_type, buf.id(), offset, length);
|
||||
}
|
||||
|
||||
void copy_from(buffer_view &view)
|
||||
{
|
||||
copy_from(*view.value(), view.format(), view.offset(), view.range());
|
||||
}
|
||||
|
||||
void copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
pixel_settings.apply();
|
||||
const auto& caps = get_driver_caps();
|
||||
|
||||
if (!region.x && !region.y && !region.z &&
|
||||
region.width == m_width && region.height == m_height && region.depth == m_depth)
|
||||
{
|
||||
if (caps.ARB_dsa_supported)
|
||||
glGetTextureImage(m_id, level, static_cast<GLenum>(format), static_cast<GLenum>(type), s32{smax}, dst);
|
||||
else
|
||||
glGetTextureImageEXT(m_id, static_cast<GLenum>(m_target), level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst);
|
||||
}
|
||||
else if (caps.ARB_dsa_supported)
|
||||
{
|
||||
glGetTextureSubImage(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth,
|
||||
static_cast<GLenum>(format), static_cast<GLenum>(type), s32{smax}, dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Worst case scenario. For some reason, EXT_dsa does not have glGetTextureSubImage
|
||||
const auto target_ = static_cast<GLenum>(m_target);
|
||||
texture tmp{ target_, region.width, region.height, region.depth, 1, static_cast<GLenum>(m_internal_format) };
|
||||
glCopyImageSubData(m_id, target_, level, region.x, region.y, region.z, tmp.id(), target_, 0, 0, 0, 0,
|
||||
region.width, region.height, region.depth);
|
||||
|
||||
const coord3u region2 = { {0, 0, 0}, region.size };
|
||||
tmp.copy_to(dst, format, type, 0, region2, pixel_settings);
|
||||
}
|
||||
}
|
||||
|
||||
void copy_to(void* dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
const coord3u region = { {}, size3D() };
|
||||
copy_to(dst, format, type, 0, region, pixel_settings);
|
||||
}
|
||||
};
|
||||
|
||||
class texture_view
|
||||
{
|
||||
GLuint m_id = GL_NONE;
|
||||
GLenum m_target = 0;
|
||||
GLenum m_format = 0;
|
||||
GLenum m_aspect_flags = 0;
|
||||
texture *m_image_data = nullptr;
|
||||
|
||||
GLenum component_swizzle[4];
|
||||
|
||||
void create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr)
|
||||
{
|
||||
m_target = target;
|
||||
m_format = sized_format;
|
||||
m_image_data = data;
|
||||
m_aspect_flags = aspect_flags;
|
||||
|
||||
u32 num_layers;
|
||||
switch (target)
|
||||
{
|
||||
default:
|
||||
num_layers = 1; break;
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
num_layers = 6; break;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
num_layers = data->depth(); break;
|
||||
}
|
||||
|
||||
glGenTextures(1, &m_id);
|
||||
glTextureView(m_id, target, data->id(), sized_format, 0, data->levels(), 0, num_layers);
|
||||
|
||||
if (argb_swizzle)
|
||||
{
|
||||
component_swizzle[0] = argb_swizzle[1];
|
||||
component_swizzle[1] = argb_swizzle[2];
|
||||
component_swizzle[2] = argb_swizzle[3];
|
||||
component_swizzle[3] = argb_swizzle[0];
|
||||
|
||||
texture::save_binding_state save(m_target);
|
||||
glBindTexture(m_target, m_id);
|
||||
glTexParameteriv(m_target, GL_TEXTURE_SWIZZLE_RGBA, reinterpret_cast<GLint*>(component_swizzle));
|
||||
}
|
||||
else
|
||||
{
|
||||
component_swizzle[0] = GL_RED;
|
||||
component_swizzle[1] = GL_GREEN;
|
||||
component_swizzle[2] = GL_BLUE;
|
||||
component_swizzle[3] = GL_ALPHA;
|
||||
}
|
||||
|
||||
if (aspect_flags & image_aspect::stencil)
|
||||
{
|
||||
constexpr u32 depth_stencil_mask = (image_aspect::depth | image_aspect::stencil);
|
||||
ensure((aspect_flags & depth_stencil_mask) != depth_stencil_mask); // "Invalid aspect mask combination"
|
||||
|
||||
texture::save_binding_state save(m_target);
|
||||
glBindTexture(m_target, m_id);
|
||||
glTexParameteri(m_target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
texture_view(const texture_view&) = delete;
|
||||
texture_view(texture_view&&) = delete;
|
||||
|
||||
texture_view(texture* data, GLenum target, GLenum sized_format,
|
||||
const GLenum* argb_swizzle = nullptr,
|
||||
GLenum aspect_flags = image_aspect::color | image_aspect::depth)
|
||||
{
|
||||
create(data, target, sized_format, aspect_flags, argb_swizzle);
|
||||
}
|
||||
|
||||
texture_view(texture* data, const GLenum* argb_swizzle = nullptr,
|
||||
GLenum aspect_flags = image_aspect::color | image_aspect::depth)
|
||||
{
|
||||
GLenum target = static_cast<GLenum>(data->get_target());
|
||||
GLenum sized_format = static_cast<GLenum>(data->get_internal_format());
|
||||
create(data, target, sized_format, aspect_flags, argb_swizzle);
|
||||
}
|
||||
|
||||
~texture_view()
|
||||
{
|
||||
if (m_id != GL_NONE)
|
||||
{
|
||||
glDeleteTextures(1, &m_id);
|
||||
m_id = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
GLenum target() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
GLenum internal_format() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
GLenum aspect() const
|
||||
{
|
||||
return m_aspect_flags;
|
||||
}
|
||||
|
||||
bool compare_swizzle(const GLenum* argb_swizzle) const
|
||||
{
|
||||
return (argb_swizzle[0] == component_swizzle[3] &&
|
||||
argb_swizzle[1] == component_swizzle[0] &&
|
||||
argb_swizzle[2] == component_swizzle[1] &&
|
||||
argb_swizzle[3] == component_swizzle[2]);
|
||||
}
|
||||
|
||||
void bind(gl::command_context& cmd, GLuint layer) const
|
||||
{
|
||||
cmd->bind_texture(layer, m_target, m_id);
|
||||
}
|
||||
|
||||
texture* image() const
|
||||
{
|
||||
return m_image_data;
|
||||
}
|
||||
|
||||
std::array<GLenum, 4> component_mapping() const
|
||||
{
|
||||
return{ component_swizzle[3], component_swizzle[0], component_swizzle[1], component_swizzle[2] };
|
||||
}
|
||||
|
||||
u32 encoded_component_map() const
|
||||
{
|
||||
// Unused, OGL supports proper component swizzles
|
||||
return 0u;
|
||||
}
|
||||
};
|
||||
|
||||
class viewable_image : public texture
|
||||
{
|
||||
std::unordered_multimap<u32, std::unique_ptr<texture_view>> views;
|
||||
|
||||
public:
|
||||
using texture::texture;
|
||||
|
||||
texture_view* get_view(u32 remap_encoding, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap, GLenum aspect_flags = image_aspect::color | image_aspect::depth)
|
||||
{
|
||||
auto found = views.equal_range(remap_encoding);
|
||||
for (auto It = found.first; It != found.second; ++It)
|
||||
{
|
||||
if (It->second->aspect() & aspect_flags)
|
||||
{
|
||||
return It->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
ensure(aspect() & aspect_flags);
|
||||
auto mapping = apply_swizzle_remap(get_native_component_layout(), remap);
|
||||
auto view = std::make_unique<texture_view>(this, mapping.data(), aspect_flags);
|
||||
auto result = view.get();
|
||||
views.emplace(remap_encoding, std::move(view));
|
||||
return result;
|
||||
}
|
||||
|
||||
void set_native_component_layout(const std::array<GLenum, 4>& layout)
|
||||
{
|
||||
if (m_component_layout[0] != layout[0] ||
|
||||
m_component_layout[1] != layout[1] ||
|
||||
m_component_layout[2] != layout[2] ||
|
||||
m_component_layout[3] != layout[3])
|
||||
{
|
||||
texture::set_native_component_layout(layout);
|
||||
views.clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class rbo
|
||||
{
|
||||
GLuint m_id = GL_NONE;
|
||||
|
33
rpcs3/Emu/RSX/GL/glutils/common.cpp
Normal file
33
rpcs3/Emu/RSX/GL/glutils/common.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "state_tracker.hpp"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
static thread_local bool s_tls_primary_context_thread = false;
|
||||
static gl::driver_state* s_current_state = nullptr;
|
||||
|
||||
void set_primary_context_thread(bool value)
|
||||
{
|
||||
s_tls_primary_context_thread = value;
|
||||
}
|
||||
|
||||
bool is_primary_context_thread()
|
||||
{
|
||||
return s_tls_primary_context_thread;
|
||||
}
|
||||
|
||||
void set_command_context(gl::command_context& ctx)
|
||||
{
|
||||
s_current_state = ctx.operator->();
|
||||
}
|
||||
|
||||
void set_command_context(gl::driver_state& ctx)
|
||||
{
|
||||
s_current_state = &ctx;
|
||||
}
|
||||
|
||||
gl::command_context get_command_context()
|
||||
{
|
||||
return { *s_current_state };
|
||||
}
|
||||
}
|
@ -2,6 +2,26 @@
|
||||
|
||||
#include "capabilities.hpp"
|
||||
|
||||
#define GL_FRAGMENT_TEXTURES_START 0
|
||||
#define GL_VERTEX_TEXTURES_START (GL_FRAGMENT_TEXTURES_START + 16)
|
||||
#define GL_STENCIL_MIRRORS_START (GL_VERTEX_TEXTURES_START + 4)
|
||||
#define GL_STREAM_BUFFER_START (GL_STENCIL_MIRRORS_START + 16)
|
||||
#define GL_TEMP_IMAGE_SLOT 31
|
||||
|
||||
#define UBO_SLOT(x) (x)
|
||||
#define SSBO_SLOT(x) (x)
|
||||
|
||||
#define GL_VERTEX_PARAMS_BIND_SLOT UBO_SLOT(0)
|
||||
#define GL_VERTEX_LAYOUT_BIND_SLOT UBO_SLOT(1)
|
||||
#define GL_VERTEX_CONSTANT_BUFFERS_BIND_SLOT UBO_SLOT(2)
|
||||
#define GL_FRAGMENT_CONSTANT_BUFFERS_BIND_SLOT UBO_SLOT(3)
|
||||
#define GL_FRAGMENT_STATE_BIND_SLOT UBO_SLOT(4)
|
||||
#define GL_FRAGMENT_TEXTURE_PARAMS_BIND_SLOT UBO_SLOT(5)
|
||||
#define GL_RASTERIZER_STATE_BIND_SLOT UBO_SLOT(6)
|
||||
#define GL_INTERPRETER_VERTEX_BLOCK SSBO_SLOT(0)
|
||||
#define GL_INTERPRETER_FRAGMENT_BLOCK SSBO_SLOT(1)
|
||||
#define GL_COMPUTE_BUFFER_SLOT(index) SSBO_SLOT(2 + index)
|
||||
|
||||
//Function call wrapped in ARB_DSA vs EXT_DSA compat check
|
||||
#define DSA_CALL(func, object_name, target, ...)\
|
||||
if (::gl::get_driver_caps().ARB_dsa_supported)\
|
||||
|
298
rpcs3/Emu/RSX/GL/glutils/image.cpp
Normal file
298
rpcs3/Emu/RSX/GL/glutils/image.cpp
Normal file
@ -0,0 +1,298 @@
|
||||
#include "stdafx.h"
|
||||
#include "image.h"
|
||||
#include "buffer_object.h"
|
||||
#include "state_tracker.hpp"
|
||||
#include "pixel_settings.hpp"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
texture::texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLenum sized_format, rsx::format_class format_class)
|
||||
{
|
||||
glGenTextures(1, &m_id);
|
||||
|
||||
// Must bind to initialize the new texture
|
||||
gl::get_command_context()->bind_texture(GL_TEMP_IMAGE_SLOT, target, m_id);
|
||||
|
||||
switch (target)
|
||||
{
|
||||
default:
|
||||
fmt::throw_exception("Invalid image target 0x%X", target);
|
||||
case GL_TEXTURE_1D:
|
||||
glTexStorage1D(target, mipmaps, sized_format, width);
|
||||
height = depth = 1;
|
||||
break;
|
||||
case GL_TEXTURE_2D:
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
glTexStorage2D(target, mipmaps, sized_format, width, height);
|
||||
depth = 1;
|
||||
break;
|
||||
case GL_TEXTURE_3D:
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
glTexStorage3D(target, mipmaps, sized_format, width, height, depth);
|
||||
break;
|
||||
case GL_TEXTURE_BUFFER:
|
||||
break;
|
||||
}
|
||||
|
||||
if (target != GL_TEXTURE_BUFFER)
|
||||
{
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
|
||||
glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
|
||||
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_depth = depth;
|
||||
m_mipmaps = mipmaps;
|
||||
m_aspect_flags = image_aspect::color;
|
||||
|
||||
switch (sized_format)
|
||||
{
|
||||
case GL_DEPTH_COMPONENT16:
|
||||
{
|
||||
m_pitch = width * 2;
|
||||
m_aspect_flags = image_aspect::depth;
|
||||
break;
|
||||
}
|
||||
case GL_DEPTH_COMPONENT32F:
|
||||
{
|
||||
m_pitch = width * 4;
|
||||
m_aspect_flags = image_aspect::depth;
|
||||
break;
|
||||
}
|
||||
case GL_DEPTH24_STENCIL8:
|
||||
case GL_DEPTH32F_STENCIL8:
|
||||
{
|
||||
m_pitch = width * 4;
|
||||
m_aspect_flags = image_aspect::depth | image_aspect::stencil;
|
||||
break;
|
||||
}
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
||||
{
|
||||
m_compressed = true;
|
||||
m_pitch = utils::align(width, 4) / 2;
|
||||
break;
|
||||
}
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
||||
{
|
||||
m_compressed = true;
|
||||
m_pitch = utils::align(width, 4);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
GLenum query_target = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target;
|
||||
GLint r, g, b, a;
|
||||
|
||||
glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_RED_SIZE, &r);
|
||||
glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_GREEN_SIZE, &g);
|
||||
glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_BLUE_SIZE, &b);
|
||||
glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_ALPHA_SIZE, &a);
|
||||
|
||||
m_pitch = width * (r + g + b + a) / 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_pitch)
|
||||
{
|
||||
fmt::throw_exception("Unhandled GL format 0x%X", sized_format);
|
||||
}
|
||||
|
||||
if (format_class == RSX_FORMAT_CLASS_UNDEFINED)
|
||||
{
|
||||
if (m_aspect_flags != image_aspect::color)
|
||||
{
|
||||
rsx_log.error("Undefined format class for depth texture is not allowed");
|
||||
}
|
||||
else
|
||||
{
|
||||
format_class = RSX_FORMAT_CLASS_COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_target = static_cast<texture::target>(target);
|
||||
m_internal_format = static_cast<internal_format>(sized_format);
|
||||
m_component_layout = { GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE };
|
||||
m_format_class = format_class;
|
||||
}
|
||||
|
||||
void texture::copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
pixel_settings.apply();
|
||||
|
||||
switch (const auto target_ = static_cast<GLenum>(m_target))
|
||||
{
|
||||
case GL_TEXTURE_1D:
|
||||
{
|
||||
DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_2D:
|
||||
{
|
||||
DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_3D:
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
{
|
||||
DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
{
|
||||
if (get_driver_caps().ARB_dsa_supported)
|
||||
{
|
||||
glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast<GLenum>(format), static_cast<GLenum>(type), src);
|
||||
}
|
||||
else
|
||||
{
|
||||
rsx_log.warning("Cubemap upload via texture::copy_from is halfplemented!");
|
||||
auto ptr = static_cast<const u8*>(src);
|
||||
const auto end = std::min(6u, region.z + region.depth);
|
||||
for (unsigned face = region.z; face < end; ++face)
|
||||
{
|
||||
glTextureSubImage2DEXT(m_id, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, region.x, region.y, region.width, region.height, static_cast<GLenum>(format), static_cast<GLenum>(type), ptr);
|
||||
ptr += (region.width * region.height * 4); //TODO
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void texture::copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length)
|
||||
{
|
||||
if (get_target() != target::textureBuffer)
|
||||
fmt::throw_exception("OpenGL error: texture cannot copy from buffer");
|
||||
|
||||
DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, gl_format_type, buf.id(), offset, length);
|
||||
}
|
||||
|
||||
void texture::copy_from(buffer_view& view)
|
||||
{
|
||||
copy_from(*view.value(), view.format(), view.offset(), view.range());
|
||||
}
|
||||
|
||||
void texture::copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
pixel_settings.apply();
|
||||
const auto& caps = get_driver_caps();
|
||||
|
||||
if (!region.x && !region.y && !region.z &&
|
||||
region.width == m_width && region.height == m_height && region.depth == m_depth)
|
||||
{
|
||||
if (caps.ARB_dsa_supported)
|
||||
glGetTextureImage(m_id, level, static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
|
||||
else
|
||||
glGetTextureImageEXT(m_id, static_cast<GLenum>(m_target), level, static_cast<GLenum>(format), static_cast<GLenum>(type), dst);
|
||||
}
|
||||
else if (caps.ARB_dsa_supported)
|
||||
{
|
||||
glGetTextureSubImage(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth,
|
||||
static_cast<GLenum>(format), static_cast<GLenum>(type), s32{ smax }, dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Worst case scenario. For some reason, EXT_dsa does not have glGetTextureSubImage
|
||||
const auto target_ = static_cast<GLenum>(m_target);
|
||||
texture tmp{ target_, region.width, region.height, region.depth, 1, static_cast<GLenum>(m_internal_format) };
|
||||
glCopyImageSubData(m_id, target_, level, region.x, region.y, region.z, tmp.id(), target_, 0, 0, 0, 0,
|
||||
region.width, region.height, region.depth);
|
||||
|
||||
const coord3u region2 = { {0, 0, 0}, region.size };
|
||||
tmp.copy_to(dst, format, type, 0, region2, pixel_settings);
|
||||
}
|
||||
}
|
||||
|
||||
void texture_view::create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle)
|
||||
{
|
||||
m_target = target;
|
||||
m_format = sized_format;
|
||||
m_image_data = data;
|
||||
m_aspect_flags = aspect_flags;
|
||||
|
||||
u32 num_layers;
|
||||
switch (target)
|
||||
{
|
||||
default:
|
||||
num_layers = 1; break;
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
num_layers = 6; break;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
num_layers = data->depth(); break;
|
||||
}
|
||||
|
||||
glGenTextures(1, &m_id);
|
||||
glTextureView(m_id, target, data->id(), sized_format, 0, data->levels(), 0, num_layers);
|
||||
|
||||
if (argb_swizzle)
|
||||
{
|
||||
component_swizzle[0] = argb_swizzle[1];
|
||||
component_swizzle[1] = argb_swizzle[2];
|
||||
component_swizzle[2] = argb_swizzle[3];
|
||||
component_swizzle[3] = argb_swizzle[0];
|
||||
|
||||
gl::get_command_context()->bind_texture(GL_TEMP_IMAGE_SLOT, m_target, m_id);
|
||||
glTexParameteriv(m_target, GL_TEXTURE_SWIZZLE_RGBA, reinterpret_cast<GLint*>(component_swizzle));
|
||||
}
|
||||
else
|
||||
{
|
||||
component_swizzle[0] = GL_RED;
|
||||
component_swizzle[1] = GL_GREEN;
|
||||
component_swizzle[2] = GL_BLUE;
|
||||
component_swizzle[3] = GL_ALPHA;
|
||||
}
|
||||
|
||||
if (aspect_flags & image_aspect::stencil)
|
||||
{
|
||||
constexpr u32 depth_stencil_mask = (image_aspect::depth | image_aspect::stencil);
|
||||
ensure((aspect_flags & depth_stencil_mask) != depth_stencil_mask); // "Invalid aspect mask combination"
|
||||
|
||||
gl::get_command_context()->bind_texture(GL_TEMP_IMAGE_SLOT, m_target, m_id);
|
||||
glTexParameteri(m_target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
void texture_view::bind(gl::command_context& cmd, GLuint layer) const
|
||||
{
|
||||
cmd->bind_texture(layer, m_target, m_id);
|
||||
}
|
||||
|
||||
texture_view* viewable_image::get_view(u32 remap_encoding, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap, GLenum aspect_flags)
|
||||
{
|
||||
auto found = views.equal_range(remap_encoding);
|
||||
for (auto It = found.first; It != found.second; ++It)
|
||||
{
|
||||
if (It->second->aspect() & aspect_flags)
|
||||
{
|
||||
return It->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
ensure(aspect() & aspect_flags);
|
||||
auto mapping = apply_swizzle_remap(get_native_component_layout(), remap);
|
||||
auto view = std::make_unique<texture_view>(this, mapping.data(), aspect_flags);
|
||||
auto result = view.get();
|
||||
views.emplace(remap_encoding, std::move(view));
|
||||
return result;
|
||||
}
|
||||
|
||||
void viewable_image::set_native_component_layout(const std::array<GLenum, 4>& layout)
|
||||
{
|
||||
if (m_component_layout[0] != layout[0] ||
|
||||
m_component_layout[1] != layout[1] ||
|
||||
m_component_layout[2] != layout[2] ||
|
||||
m_component_layout[3] != layout[3])
|
||||
{
|
||||
texture::set_native_component_layout(layout);
|
||||
views.clear();
|
||||
}
|
||||
}
|
||||
}
|
393
rpcs3/Emu/RSX/GL/glutils/image.h
Normal file
393
rpcs3/Emu/RSX/GL/glutils/image.h
Normal file
@ -0,0 +1,393 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "Utilities/geometry.h"
|
||||
#include "Emu/RSX/Common/TextureUtils.h"
|
||||
|
||||
//using enum rsx::format_class;
|
||||
using namespace ::rsx::format_class_;
|
||||
|
||||
namespace gl
|
||||
{
|
||||
class buffer;
|
||||
class buffer_view;
|
||||
class command_context;
|
||||
class pixel_pack_settings;
|
||||
class pixel_unpack_settings;
|
||||
|
||||
enum image_aspect : u32
|
||||
{
|
||||
color = 1,
|
||||
depth = 2,
|
||||
stencil = 4
|
||||
};
|
||||
|
||||
class texture
|
||||
{
|
||||
friend class texture_view;
|
||||
|
||||
public:
|
||||
enum class type
|
||||
{
|
||||
ubyte = GL_UNSIGNED_BYTE,
|
||||
ushort = GL_UNSIGNED_SHORT,
|
||||
uint = GL_UNSIGNED_INT,
|
||||
|
||||
ubyte_3_3_2 = GL_UNSIGNED_BYTE_3_3_2,
|
||||
ubyte_2_3_3_rev = GL_UNSIGNED_BYTE_2_3_3_REV,
|
||||
|
||||
ushort_5_6_5 = GL_UNSIGNED_SHORT_5_6_5,
|
||||
ushort_5_6_5_rev = GL_UNSIGNED_SHORT_5_6_5_REV,
|
||||
ushort_4_4_4_4 = GL_UNSIGNED_SHORT_4_4_4_4,
|
||||
ushort_4_4_4_4_rev = GL_UNSIGNED_SHORT_4_4_4_4_REV,
|
||||
ushort_5_5_5_1 = GL_UNSIGNED_SHORT_5_5_5_1,
|
||||
ushort_1_5_5_5_rev = GL_UNSIGNED_SHORT_1_5_5_5_REV,
|
||||
|
||||
uint_8_8_8_8 = GL_UNSIGNED_INT_8_8_8_8,
|
||||
uint_8_8_8_8_rev = GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
uint_10_10_10_2 = GL_UNSIGNED_INT_10_10_10_2,
|
||||
uint_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
uint_24_8 = GL_UNSIGNED_INT_24_8,
|
||||
float32_uint8 = GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
|
||||
|
||||
sbyte = GL_BYTE,
|
||||
sshort = GL_SHORT,
|
||||
sint = GL_INT,
|
||||
f16 = GL_HALF_FLOAT,
|
||||
f32 = GL_FLOAT,
|
||||
f64 = GL_DOUBLE,
|
||||
};
|
||||
|
||||
enum class channel
|
||||
{
|
||||
zero = GL_ZERO,
|
||||
one = GL_ONE,
|
||||
r = GL_RED,
|
||||
g = GL_GREEN,
|
||||
b = GL_BLUE,
|
||||
a = GL_ALPHA,
|
||||
};
|
||||
|
||||
enum class format
|
||||
{
|
||||
r = GL_RED,
|
||||
rg = GL_RG,
|
||||
rgb = GL_RGB,
|
||||
rgba = GL_RGBA,
|
||||
|
||||
bgr = GL_BGR,
|
||||
bgra = GL_BGRA,
|
||||
|
||||
stencil = GL_STENCIL_INDEX,
|
||||
depth = GL_DEPTH_COMPONENT,
|
||||
depth_stencil = GL_DEPTH_STENCIL
|
||||
};
|
||||
|
||||
enum class internal_format
|
||||
{
|
||||
stencil8 = GL_STENCIL_INDEX8,
|
||||
depth16 = GL_DEPTH_COMPONENT16,
|
||||
depth32f = GL_DEPTH_COMPONENT32F,
|
||||
depth24_stencil8 = GL_DEPTH24_STENCIL8,
|
||||
depth32f_stencil8 = GL_DEPTH32F_STENCIL8,
|
||||
|
||||
compressed_rgb_s3tc_dxt1 = GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
|
||||
compressed_rgba_s3tc_dxt1 = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
|
||||
compressed_rgba_s3tc_dxt3 = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
|
||||
compressed_rgba_s3tc_dxt5 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
|
||||
|
||||
//Sized internal formats, see opengl spec document on glTexImage2D, table 3
|
||||
rgba8 = GL_RGBA8,
|
||||
rgb565 = GL_RGB565,
|
||||
rgb5a1 = GL_RGB5_A1,
|
||||
rgba4 = GL_RGBA4,
|
||||
r8 = GL_R8,
|
||||
r16 = GL_R16,
|
||||
r32f = GL_R32F,
|
||||
rg8 = GL_RG8,
|
||||
rg16 = GL_RG16,
|
||||
rg16f = GL_RG16F,
|
||||
rgba16f = GL_RGBA16F,
|
||||
rgba32f = GL_RGBA32F
|
||||
};
|
||||
|
||||
enum class wrap
|
||||
{
|
||||
repeat = GL_REPEAT,
|
||||
mirrored_repeat = GL_MIRRORED_REPEAT,
|
||||
clamp_to_edge = GL_CLAMP_TO_EDGE,
|
||||
clamp_to_border = GL_CLAMP_TO_BORDER,
|
||||
mirror_clamp = GL_MIRROR_CLAMP_EXT,
|
||||
//mirror_clamp_to_edge = GL_MIRROR_CLAMP_TO_EDGE,
|
||||
mirror_clamp_to_border = GL_MIRROR_CLAMP_TO_BORDER_EXT
|
||||
};
|
||||
|
||||
enum class compare_mode
|
||||
{
|
||||
none = GL_NONE,
|
||||
ref_to_texture = GL_COMPARE_REF_TO_TEXTURE
|
||||
};
|
||||
|
||||
enum class target
|
||||
{
|
||||
texture1D = GL_TEXTURE_1D,
|
||||
texture2D = GL_TEXTURE_2D,
|
||||
texture3D = GL_TEXTURE_3D,
|
||||
textureCUBE = GL_TEXTURE_CUBE_MAP,
|
||||
textureBuffer = GL_TEXTURE_BUFFER
|
||||
};
|
||||
|
||||
protected:
|
||||
GLuint m_id = GL_NONE;
|
||||
GLuint m_width = 0;
|
||||
GLuint m_height = 0;
|
||||
GLuint m_depth = 0;
|
||||
GLuint m_mipmaps = 0;
|
||||
GLuint m_pitch = 0;
|
||||
GLuint m_compressed = GL_FALSE;
|
||||
GLuint m_aspect_flags = 0;
|
||||
|
||||
target m_target = target::texture2D;
|
||||
internal_format m_internal_format = internal_format::rgba8;
|
||||
std::array<GLenum, 4> m_component_layout;
|
||||
|
||||
rsx::format_class m_format_class = RSX_FORMAT_CLASS_UNDEFINED;
|
||||
|
||||
public:
|
||||
texture(const texture&) = delete;
|
||||
texture(texture&& texture_) = delete;
|
||||
|
||||
texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLenum sized_format, rsx::format_class format_class = rsx::RSX_FORMAT_CLASS_UNDEFINED);
|
||||
|
||||
virtual ~texture()
|
||||
{
|
||||
glDeleteTextures(1, &m_id);
|
||||
m_id = GL_NONE;
|
||||
}
|
||||
|
||||
// Getters/setters
|
||||
void set_native_component_layout(const std::array<GLenum, 4>& layout)
|
||||
{
|
||||
m_component_layout[0] = layout[0];
|
||||
m_component_layout[1] = layout[1];
|
||||
m_component_layout[2] = layout[2];
|
||||
m_component_layout[3] = layout[3];
|
||||
}
|
||||
|
||||
target get_target() const noexcept
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
static bool compressed_format(internal_format format_) noexcept
|
||||
{
|
||||
switch (format_)
|
||||
{
|
||||
case internal_format::compressed_rgb_s3tc_dxt1:
|
||||
case internal_format::compressed_rgba_s3tc_dxt1:
|
||||
case internal_format::compressed_rgba_s3tc_dxt3:
|
||||
case internal_format::compressed_rgba_s3tc_dxt5:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint id() const noexcept
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return (m_id != GL_NONE);
|
||||
}
|
||||
|
||||
GLuint width() const
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
GLuint height() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
GLuint depth() const
|
||||
{
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
GLuint levels() const
|
||||
{
|
||||
return m_mipmaps;
|
||||
}
|
||||
|
||||
GLuint pitch() const
|
||||
{
|
||||
return m_pitch;
|
||||
}
|
||||
|
||||
constexpr GLubyte samples() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
GLboolean compressed() const
|
||||
{
|
||||
return m_compressed;
|
||||
}
|
||||
|
||||
GLuint aspect() const
|
||||
{
|
||||
return m_aspect_flags;
|
||||
}
|
||||
|
||||
rsx::format_class format_class() const
|
||||
{
|
||||
return m_format_class;
|
||||
}
|
||||
|
||||
sizeu size2D() const
|
||||
{
|
||||
return{ m_width, m_height };
|
||||
}
|
||||
|
||||
size3u size3D() const
|
||||
{
|
||||
const auto depth = (m_target == target::textureCUBE) ? 6 : m_depth;
|
||||
return{ m_width, m_height, depth };
|
||||
}
|
||||
|
||||
texture::internal_format get_internal_format() const
|
||||
{
|
||||
return m_internal_format;
|
||||
}
|
||||
|
||||
std::array<GLenum, 4> get_native_component_layout() const
|
||||
{
|
||||
return m_component_layout;
|
||||
}
|
||||
|
||||
// Data management
|
||||
void copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings);
|
||||
|
||||
void copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length);
|
||||
|
||||
void copy_from(buffer_view& view);
|
||||
|
||||
void copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const;
|
||||
|
||||
// Convenience wrappers
|
||||
void copy_from(const void* src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings)
|
||||
{
|
||||
const coord3u region = { {}, size3D() };
|
||||
copy_from(src, format, type, 0, region, pixel_settings);
|
||||
}
|
||||
|
||||
void copy_to(void* dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const
|
||||
{
|
||||
const coord3u region = { {}, size3D() };
|
||||
copy_to(dst, format, type, 0, region, pixel_settings);
|
||||
}
|
||||
};
|
||||
|
||||
class texture_view
|
||||
{
|
||||
GLuint m_id = GL_NONE;
|
||||
GLenum m_target = 0;
|
||||
GLenum m_format = 0;
|
||||
GLenum m_aspect_flags = 0;
|
||||
texture* m_image_data = nullptr;
|
||||
|
||||
GLenum component_swizzle[4];
|
||||
|
||||
void create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr);
|
||||
|
||||
public:
|
||||
texture_view(const texture_view&) = delete;
|
||||
texture_view(texture_view&&) = delete;
|
||||
|
||||
texture_view(texture* data, GLenum target, GLenum sized_format,
|
||||
const GLenum* argb_swizzle = nullptr,
|
||||
GLenum aspect_flags = image_aspect::color | image_aspect::depth)
|
||||
{
|
||||
create(data, target, sized_format, aspect_flags, argb_swizzle);
|
||||
}
|
||||
|
||||
texture_view(texture* data, const GLenum* argb_swizzle = nullptr,
|
||||
GLenum aspect_flags = image_aspect::color | image_aspect::depth)
|
||||
{
|
||||
GLenum target = static_cast<GLenum>(data->get_target());
|
||||
GLenum sized_format = static_cast<GLenum>(data->get_internal_format());
|
||||
create(data, target, sized_format, aspect_flags, argb_swizzle);
|
||||
}
|
||||
|
||||
virtual ~texture_view()
|
||||
{
|
||||
glDeleteTextures(1, &m_id);
|
||||
m_id = GL_NONE;
|
||||
}
|
||||
|
||||
GLuint id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
GLenum target() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
GLenum internal_format() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
GLenum aspect() const
|
||||
{
|
||||
return m_aspect_flags;
|
||||
}
|
||||
|
||||
bool compare_swizzle(const GLenum* argb_swizzle) const
|
||||
{
|
||||
return (argb_swizzle[0] == component_swizzle[3] &&
|
||||
argb_swizzle[1] == component_swizzle[0] &&
|
||||
argb_swizzle[2] == component_swizzle[1] &&
|
||||
argb_swizzle[3] == component_swizzle[2]);
|
||||
}
|
||||
|
||||
texture* image() const
|
||||
{
|
||||
return m_image_data;
|
||||
}
|
||||
|
||||
std::array<GLenum, 4> component_mapping() const
|
||||
{
|
||||
return{ component_swizzle[3], component_swizzle[0], component_swizzle[1], component_swizzle[2] };
|
||||
}
|
||||
|
||||
u32 encoded_component_map() const
|
||||
{
|
||||
// Unused, OGL supports proper component swizzles
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void bind(gl::command_context& cmd, GLuint layer) const;
|
||||
};
|
||||
|
||||
class viewable_image : public texture
|
||||
{
|
||||
std::unordered_multimap<u32, std::unique_ptr<texture_view>> views;
|
||||
|
||||
public:
|
||||
using texture::texture;
|
||||
|
||||
texture_view* get_view(u32 remap_encoding, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap, GLenum aspect_flags = image_aspect::color | image_aspect::depth);
|
||||
void set_native_component_layout(const std::array<GLenum, 4>& layout);
|
||||
};
|
||||
|
||||
// Texture helpers
|
||||
std::array<GLenum, 4> apply_swizzle_remap(const std::array<GLenum, 4>& swizzle_remap, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& decoded_remap);
|
||||
}
|
157
rpcs3/Emu/RSX/GL/glutils/pixel_settings.hpp
Normal file
157
rpcs3/Emu/RSX/GL/glutils/pixel_settings.hpp
Normal file
@ -0,0 +1,157 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
class pixel_pack_settings
|
||||
{
|
||||
bool m_swap_bytes = false;
|
||||
bool m_lsb_first = false;
|
||||
int m_row_length = 0;
|
||||
int m_image_height = 0;
|
||||
int m_skip_rows = 0;
|
||||
int m_skip_pixels = 0;
|
||||
int m_skip_images = 0;
|
||||
int m_alignment = 4;
|
||||
|
||||
public:
|
||||
void apply() const
|
||||
{
|
||||
glPixelStorei(GL_PACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE);
|
||||
glPixelStorei(GL_PACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, m_row_length);
|
||||
glPixelStorei(GL_PACK_IMAGE_HEIGHT, m_image_height);
|
||||
glPixelStorei(GL_PACK_SKIP_ROWS, m_skip_rows);
|
||||
glPixelStorei(GL_PACK_SKIP_PIXELS, m_skip_pixels);
|
||||
glPixelStorei(GL_PACK_SKIP_IMAGES, m_skip_images);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, m_alignment);
|
||||
}
|
||||
|
||||
pixel_pack_settings& swap_bytes(bool value = true)
|
||||
{
|
||||
m_swap_bytes = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& lsb_first(bool value = true)
|
||||
{
|
||||
m_lsb_first = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& row_length(int value)
|
||||
{
|
||||
m_row_length = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& image_height(int value)
|
||||
{
|
||||
m_image_height = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& skip_rows(int value)
|
||||
{
|
||||
m_skip_rows = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& skip_pixels(int value)
|
||||
{
|
||||
m_skip_pixels = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& skip_images(int value)
|
||||
{
|
||||
m_skip_images = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_pack_settings& alignment(int value)
|
||||
{
|
||||
m_alignment = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool get_swap_bytes() const
|
||||
{
|
||||
return m_swap_bytes;
|
||||
}
|
||||
int get_row_length() const
|
||||
{
|
||||
return m_row_length;
|
||||
}
|
||||
};
|
||||
|
||||
class pixel_unpack_settings
|
||||
{
|
||||
bool m_swap_bytes = false;
|
||||
bool m_lsb_first = false;
|
||||
int m_row_length = 0;
|
||||
int m_image_height = 0;
|
||||
int m_skip_rows = 0;
|
||||
int m_skip_pixels = 0;
|
||||
int m_skip_images = 0;
|
||||
int m_alignment = 4;
|
||||
|
||||
public:
|
||||
void apply() const
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE);
|
||||
glPixelStorei(GL_UNPACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, m_row_length);
|
||||
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_image_height);
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, m_skip_rows);
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_skip_pixels);
|
||||
glPixelStorei(GL_UNPACK_SKIP_IMAGES, m_skip_images);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment);
|
||||
}
|
||||
|
||||
pixel_unpack_settings& swap_bytes(bool value = true)
|
||||
{
|
||||
m_swap_bytes = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& lsb_first(bool value = true)
|
||||
{
|
||||
m_lsb_first = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& row_length(int value)
|
||||
{
|
||||
m_row_length = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& image_height(int value)
|
||||
{
|
||||
m_image_height = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& skip_rows(int value)
|
||||
{
|
||||
m_skip_rows = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& skip_pixels(int value)
|
||||
{
|
||||
m_skip_pixels = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& skip_images(int value)
|
||||
{
|
||||
m_skip_images = value;
|
||||
return *this;
|
||||
}
|
||||
pixel_unpack_settings& alignment(int value)
|
||||
{
|
||||
m_alignment = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool get_swap_bytes() const
|
||||
{
|
||||
return m_swap_bytes;
|
||||
}
|
||||
|
||||
int get_row_length() const
|
||||
{
|
||||
return m_row_length;
|
||||
}
|
||||
};
|
||||
}
|
@ -1,322 +1,329 @@
|
||||
#pragma once
|
||||
|
||||
#include "glutils/capabilities.hpp"
|
||||
|
||||
#include "Utilities/geometry.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace gl
|
||||
{
|
||||
struct driver_state
|
||||
{
|
||||
const u32 DEPTH_BOUNDS_MIN = 0xFFFF0001;
|
||||
const u32 DEPTH_BOUNDS_MAX = 0xFFFF0002;
|
||||
const u32 DEPTH_RANGE_MIN = 0xFFFF0003;
|
||||
const u32 DEPTH_RANGE_MAX = 0xFFFF0004;
|
||||
|
||||
std::unordered_map<GLenum, u32> properties = {};
|
||||
std::unordered_map<GLenum, std::array<u32, 4>> indexed_properties = {};
|
||||
|
||||
GLuint current_program = GL_NONE;
|
||||
std::array<std::unordered_map<GLenum, GLuint>, 48> bound_textures{ {} };
|
||||
|
||||
bool enable(u32 test, GLenum cap)
|
||||
{
|
||||
auto found = properties.find(cap);
|
||||
if (found != properties.end() && found->second == test)
|
||||
return !!test;
|
||||
|
||||
properties[cap] = test;
|
||||
|
||||
if (test)
|
||||
glEnable(cap);
|
||||
else
|
||||
glDisable(cap);
|
||||
|
||||
return !!test;
|
||||
}
|
||||
|
||||
bool enablei(u32 test, GLenum cap, u32 index)
|
||||
{
|
||||
auto found = indexed_properties.find(cap);
|
||||
const bool exists = found != indexed_properties.end();
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
indexed_properties[cap] = {};
|
||||
indexed_properties[cap][index] = test;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found->second[index] == test)
|
||||
return !!test;
|
||||
|
||||
found->second[index] = test;
|
||||
}
|
||||
|
||||
if (test)
|
||||
glEnablei(cap, index);
|
||||
else
|
||||
glDisablei(cap, index);
|
||||
|
||||
return !!test;
|
||||
}
|
||||
|
||||
bool enable(GLenum cap)
|
||||
{
|
||||
return enable(GL_TRUE, cap);
|
||||
}
|
||||
|
||||
bool enablei(GLenum cap, u32 index)
|
||||
{
|
||||
return enablei(GL_TRUE, cap, index);
|
||||
}
|
||||
|
||||
bool disable(GLenum cap)
|
||||
{
|
||||
return enable(GL_FALSE, cap);
|
||||
}
|
||||
|
||||
bool disablei(GLenum cap, u32 index)
|
||||
{
|
||||
return enablei(GL_FALSE, cap, index);
|
||||
}
|
||||
|
||||
inline bool test_property(GLenum property, u32 test) const
|
||||
{
|
||||
auto found = properties.find(property);
|
||||
if (found == properties.end())
|
||||
return false;
|
||||
|
||||
return (found->second == test);
|
||||
}
|
||||
|
||||
inline bool test_propertyi(GLenum property, u32 test, GLint index) const
|
||||
{
|
||||
auto found = indexed_properties.find(property);
|
||||
if (found == indexed_properties.end())
|
||||
return false;
|
||||
|
||||
return found->second[index] == test;
|
||||
}
|
||||
|
||||
void depth_func(GLenum func)
|
||||
{
|
||||
if (!test_property(GL_DEPTH_FUNC, func))
|
||||
{
|
||||
glDepthFunc(func);
|
||||
properties[GL_DEPTH_FUNC] = func;
|
||||
}
|
||||
}
|
||||
|
||||
void depth_mask(GLboolean mask)
|
||||
{
|
||||
if (!test_property(GL_DEPTH_WRITEMASK, mask))
|
||||
{
|
||||
glDepthMask(mask);
|
||||
properties[GL_DEPTH_WRITEMASK] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_depth(GLfloat depth)
|
||||
{
|
||||
u32 value = std::bit_cast<u32>(depth);
|
||||
if (!test_property(GL_DEPTH_CLEAR_VALUE, value))
|
||||
{
|
||||
glClearDepth(depth);
|
||||
properties[GL_DEPTH_CLEAR_VALUE] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void stencil_mask(GLuint mask)
|
||||
{
|
||||
if (!test_property(GL_STENCIL_WRITEMASK, mask))
|
||||
{
|
||||
glStencilMask(mask);
|
||||
properties[GL_STENCIL_WRITEMASK] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_stencil(GLint stencil)
|
||||
{
|
||||
u32 value = std::bit_cast<u32>(stencil);
|
||||
if (!test_property(GL_STENCIL_CLEAR_VALUE, value))
|
||||
{
|
||||
glClearStencil(stencil);
|
||||
properties[GL_STENCIL_CLEAR_VALUE] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void color_maski(GLint index, u32 mask)
|
||||
{
|
||||
if (!test_propertyi(GL_COLOR_WRITEMASK, mask, index))
|
||||
{
|
||||
glColorMaski(index, ((mask & 0x10) ? 1 : 0), ((mask & 0x20) ? 1 : 0), ((mask & 0x40) ? 1 : 0), ((mask & 0x80) ? 1 : 0));
|
||||
indexed_properties[GL_COLOR_WRITEMASK][index] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void color_maski(GLint index, bool r, bool g, bool b, bool a)
|
||||
{
|
||||
u32 mask = 0;
|
||||
if (r) mask |= 0x10;
|
||||
if (g) mask |= 0x20;
|
||||
if (b) mask |= 0x40;
|
||||
if (a) mask |= 0x80;
|
||||
|
||||
color_maski(index, mask);
|
||||
}
|
||||
|
||||
void clear_color(u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
u32 value = u32{r} | u32{g} << 8 | u32{b} << 16 | u32{a} << 24;
|
||||
if (!test_property(GL_COLOR_CLEAR_VALUE, value))
|
||||
{
|
||||
glClearColor(r / 255.f, g / 255.f, b / 255.f, a / 255.f);
|
||||
properties[GL_COLOR_CLEAR_VALUE] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_color(const color4f& color)
|
||||
{
|
||||
clear_color(static_cast<u8>(color.r * 255), static_cast<u8>(color.g * 255), static_cast<u8>(color.b * 255), static_cast<u8>(color.a * 255));
|
||||
}
|
||||
|
||||
void depth_bounds(float min, float max)
|
||||
{
|
||||
u32 depth_min = std::bit_cast<u32>(min);
|
||||
u32 depth_max = std::bit_cast<u32>(max);
|
||||
|
||||
if (!test_property(DEPTH_BOUNDS_MIN, depth_min) || !test_property(DEPTH_BOUNDS_MAX, depth_max))
|
||||
{
|
||||
if (get_driver_caps().NV_depth_buffer_float_supported)
|
||||
{
|
||||
glDepthBoundsdNV(min, max);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDepthBoundsEXT(min, max);
|
||||
}
|
||||
|
||||
properties[DEPTH_BOUNDS_MIN] = depth_min;
|
||||
properties[DEPTH_BOUNDS_MAX] = depth_max;
|
||||
}
|
||||
}
|
||||
|
||||
void depth_range(float min, float max)
|
||||
{
|
||||
u32 depth_min = std::bit_cast<u32>(min);
|
||||
u32 depth_max = std::bit_cast<u32>(max);
|
||||
|
||||
if (!test_property(DEPTH_RANGE_MIN, depth_min) || !test_property(DEPTH_RANGE_MAX, depth_max))
|
||||
{
|
||||
if (get_driver_caps().NV_depth_buffer_float_supported)
|
||||
{
|
||||
glDepthRangedNV(min, max);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDepthRange(min, max);
|
||||
}
|
||||
|
||||
properties[DEPTH_RANGE_MIN] = depth_min;
|
||||
properties[DEPTH_RANGE_MAX] = depth_max;
|
||||
}
|
||||
}
|
||||
|
||||
void logic_op(GLenum op)
|
||||
{
|
||||
if (!test_property(GL_COLOR_LOGIC_OP, op))
|
||||
{
|
||||
glLogicOp(op);
|
||||
properties[GL_COLOR_LOGIC_OP] = op;
|
||||
}
|
||||
}
|
||||
|
||||
void line_width(GLfloat width)
|
||||
{
|
||||
u32 value = std::bit_cast<u32>(width);
|
||||
|
||||
if (!test_property(GL_LINE_WIDTH, value))
|
||||
{
|
||||
glLineWidth(width);
|
||||
properties[GL_LINE_WIDTH] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void front_face(GLenum face)
|
||||
{
|
||||
if (!test_property(GL_FRONT_FACE, face))
|
||||
{
|
||||
glFrontFace(face);
|
||||
properties[GL_FRONT_FACE] = face;
|
||||
}
|
||||
}
|
||||
|
||||
void cull_face(GLenum mode)
|
||||
{
|
||||
if (!test_property(GL_CULL_FACE_MODE, mode))
|
||||
{
|
||||
glCullFace(mode);
|
||||
properties[GL_CULL_FACE_MODE] = mode;
|
||||
}
|
||||
}
|
||||
|
||||
void polygon_offset(float factor, float units)
|
||||
{
|
||||
u32 _units = std::bit_cast<u32>(units);
|
||||
u32 _factor = std::bit_cast<u32>(factor);
|
||||
|
||||
if (!test_property(GL_POLYGON_OFFSET_UNITS, _units) || !test_property(GL_POLYGON_OFFSET_FACTOR, _factor))
|
||||
{
|
||||
glPolygonOffset(factor, units);
|
||||
|
||||
properties[GL_POLYGON_OFFSET_UNITS] = _units;
|
||||
properties[GL_POLYGON_OFFSET_FACTOR] = _factor;
|
||||
}
|
||||
}
|
||||
|
||||
void use_program(GLuint program)
|
||||
{
|
||||
if (current_program == program)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
current_program = program;
|
||||
glUseProgram(program);
|
||||
}
|
||||
|
||||
void bind_texture(GLuint layer, GLenum target, GLuint name)
|
||||
{
|
||||
ensure(layer < 48);
|
||||
|
||||
auto& bound = bound_textures[layer][target];
|
||||
if (bound != name)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + layer);
|
||||
glBindTexture(target, name);
|
||||
|
||||
bound = name;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class command_context
|
||||
{
|
||||
driver_state* drv;
|
||||
|
||||
public:
|
||||
command_context()
|
||||
: drv(nullptr)
|
||||
{}
|
||||
|
||||
command_context(driver_state& drv_)
|
||||
: drv(&drv_)
|
||||
{}
|
||||
|
||||
driver_state* operator -> () {
|
||||
return drv;
|
||||
}
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include "capabilities.hpp"
|
||||
|
||||
#include "Utilities/geometry.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace gl
|
||||
{
|
||||
struct driver_state
|
||||
{
|
||||
const u32 DEPTH_BOUNDS_MIN = 0xFFFF0001;
|
||||
const u32 DEPTH_BOUNDS_MAX = 0xFFFF0002;
|
||||
const u32 DEPTH_RANGE_MIN = 0xFFFF0003;
|
||||
const u32 DEPTH_RANGE_MAX = 0xFFFF0004;
|
||||
|
||||
std::unordered_map<GLenum, u32> properties = {};
|
||||
std::unordered_map<GLenum, std::array<u32, 4>> indexed_properties = {};
|
||||
|
||||
GLuint current_program = GL_NONE;
|
||||
std::array<std::unordered_map<GLenum, GLuint>, 48> bound_textures{ {} };
|
||||
|
||||
bool enable(u32 test, GLenum cap)
|
||||
{
|
||||
auto found = properties.find(cap);
|
||||
if (found != properties.end() && found->second == test)
|
||||
return !!test;
|
||||
|
||||
properties[cap] = test;
|
||||
|
||||
if (test)
|
||||
glEnable(cap);
|
||||
else
|
||||
glDisable(cap);
|
||||
|
||||
return !!test;
|
||||
}
|
||||
|
||||
bool enablei(u32 test, GLenum cap, u32 index)
|
||||
{
|
||||
auto found = indexed_properties.find(cap);
|
||||
const bool exists = found != indexed_properties.end();
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
indexed_properties[cap] = {};
|
||||
indexed_properties[cap][index] = test;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found->second[index] == test)
|
||||
return !!test;
|
||||
|
||||
found->second[index] = test;
|
||||
}
|
||||
|
||||
if (test)
|
||||
glEnablei(cap, index);
|
||||
else
|
||||
glDisablei(cap, index);
|
||||
|
||||
return !!test;
|
||||
}
|
||||
|
||||
bool enable(GLenum cap)
|
||||
{
|
||||
return enable(GL_TRUE, cap);
|
||||
}
|
||||
|
||||
bool enablei(GLenum cap, u32 index)
|
||||
{
|
||||
return enablei(GL_TRUE, cap, index);
|
||||
}
|
||||
|
||||
bool disable(GLenum cap)
|
||||
{
|
||||
return enable(GL_FALSE, cap);
|
||||
}
|
||||
|
||||
bool disablei(GLenum cap, u32 index)
|
||||
{
|
||||
return enablei(GL_FALSE, cap, index);
|
||||
}
|
||||
|
||||
inline bool test_property(GLenum property, u32 test) const
|
||||
{
|
||||
auto found = properties.find(property);
|
||||
if (found == properties.end())
|
||||
return false;
|
||||
|
||||
return (found->second == test);
|
||||
}
|
||||
|
||||
inline bool test_propertyi(GLenum property, u32 test, GLint index) const
|
||||
{
|
||||
auto found = indexed_properties.find(property);
|
||||
if (found == indexed_properties.end())
|
||||
return false;
|
||||
|
||||
return found->second[index] == test;
|
||||
}
|
||||
|
||||
void depth_func(GLenum func)
|
||||
{
|
||||
if (!test_property(GL_DEPTH_FUNC, func))
|
||||
{
|
||||
glDepthFunc(func);
|
||||
properties[GL_DEPTH_FUNC] = func;
|
||||
}
|
||||
}
|
||||
|
||||
void depth_mask(GLboolean mask)
|
||||
{
|
||||
if (!test_property(GL_DEPTH_WRITEMASK, mask))
|
||||
{
|
||||
glDepthMask(mask);
|
||||
properties[GL_DEPTH_WRITEMASK] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_depth(GLfloat depth)
|
||||
{
|
||||
u32 value = std::bit_cast<u32>(depth);
|
||||
if (!test_property(GL_DEPTH_CLEAR_VALUE, value))
|
||||
{
|
||||
glClearDepth(depth);
|
||||
properties[GL_DEPTH_CLEAR_VALUE] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void stencil_mask(GLuint mask)
|
||||
{
|
||||
if (!test_property(GL_STENCIL_WRITEMASK, mask))
|
||||
{
|
||||
glStencilMask(mask);
|
||||
properties[GL_STENCIL_WRITEMASK] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_stencil(GLint stencil)
|
||||
{
|
||||
u32 value = std::bit_cast<u32>(stencil);
|
||||
if (!test_property(GL_STENCIL_CLEAR_VALUE, value))
|
||||
{
|
||||
glClearStencil(stencil);
|
||||
properties[GL_STENCIL_CLEAR_VALUE] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void color_maski(GLint index, u32 mask)
|
||||
{
|
||||
if (!test_propertyi(GL_COLOR_WRITEMASK, mask, index))
|
||||
{
|
||||
glColorMaski(index, ((mask & 0x10) ? 1 : 0), ((mask & 0x20) ? 1 : 0), ((mask & 0x40) ? 1 : 0), ((mask & 0x80) ? 1 : 0));
|
||||
indexed_properties[GL_COLOR_WRITEMASK][index] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void color_maski(GLint index, bool r, bool g, bool b, bool a)
|
||||
{
|
||||
u32 mask = 0;
|
||||
if (r) mask |= 0x10;
|
||||
if (g) mask |= 0x20;
|
||||
if (b) mask |= 0x40;
|
||||
if (a) mask |= 0x80;
|
||||
|
||||
color_maski(index, mask);
|
||||
}
|
||||
|
||||
void clear_color(u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
u32 value = u32{ r } | u32{ g } << 8 | u32{ b } << 16 | u32{ a } << 24;
|
||||
if (!test_property(GL_COLOR_CLEAR_VALUE, value))
|
||||
{
|
||||
glClearColor(r / 255.f, g / 255.f, b / 255.f, a / 255.f);
|
||||
properties[GL_COLOR_CLEAR_VALUE] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_color(const color4f& color)
|
||||
{
|
||||
clear_color(static_cast<u8>(color.r * 255), static_cast<u8>(color.g * 255), static_cast<u8>(color.b * 255), static_cast<u8>(color.a * 255));
|
||||
}
|
||||
|
||||
void depth_bounds(float min, float max)
|
||||
{
|
||||
u32 depth_min = std::bit_cast<u32>(min);
|
||||
u32 depth_max = std::bit_cast<u32>(max);
|
||||
|
||||
if (!test_property(DEPTH_BOUNDS_MIN, depth_min) || !test_property(DEPTH_BOUNDS_MAX, depth_max))
|
||||
{
|
||||
if (get_driver_caps().NV_depth_buffer_float_supported)
|
||||
{
|
||||
glDepthBoundsdNV(min, max);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDepthBoundsEXT(min, max);
|
||||
}
|
||||
|
||||
properties[DEPTH_BOUNDS_MIN] = depth_min;
|
||||
properties[DEPTH_BOUNDS_MAX] = depth_max;
|
||||
}
|
||||
}
|
||||
|
||||
void depth_range(float min, float max)
|
||||
{
|
||||
u32 depth_min = std::bit_cast<u32>(min);
|
||||
u32 depth_max = std::bit_cast<u32>(max);
|
||||
|
||||
if (!test_property(DEPTH_RANGE_MIN, depth_min) || !test_property(DEPTH_RANGE_MAX, depth_max))
|
||||
{
|
||||
if (get_driver_caps().NV_depth_buffer_float_supported)
|
||||
{
|
||||
glDepthRangedNV(min, max);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDepthRange(min, max);
|
||||
}
|
||||
|
||||
properties[DEPTH_RANGE_MIN] = depth_min;
|
||||
properties[DEPTH_RANGE_MAX] = depth_max;
|
||||
}
|
||||
}
|
||||
|
||||
void logic_op(GLenum op)
|
||||
{
|
||||
if (!test_property(GL_COLOR_LOGIC_OP, op))
|
||||
{
|
||||
glLogicOp(op);
|
||||
properties[GL_COLOR_LOGIC_OP] = op;
|
||||
}
|
||||
}
|
||||
|
||||
void line_width(GLfloat width)
|
||||
{
|
||||
u32 value = std::bit_cast<u32>(width);
|
||||
|
||||
if (!test_property(GL_LINE_WIDTH, value))
|
||||
{
|
||||
glLineWidth(width);
|
||||
properties[GL_LINE_WIDTH] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void front_face(GLenum face)
|
||||
{
|
||||
if (!test_property(GL_FRONT_FACE, face))
|
||||
{
|
||||
glFrontFace(face);
|
||||
properties[GL_FRONT_FACE] = face;
|
||||
}
|
||||
}
|
||||
|
||||
void cull_face(GLenum mode)
|
||||
{
|
||||
if (!test_property(GL_CULL_FACE_MODE, mode))
|
||||
{
|
||||
glCullFace(mode);
|
||||
properties[GL_CULL_FACE_MODE] = mode;
|
||||
}
|
||||
}
|
||||
|
||||
void polygon_offset(float factor, float units)
|
||||
{
|
||||
u32 _units = std::bit_cast<u32>(units);
|
||||
u32 _factor = std::bit_cast<u32>(factor);
|
||||
|
||||
if (!test_property(GL_POLYGON_OFFSET_UNITS, _units) || !test_property(GL_POLYGON_OFFSET_FACTOR, _factor))
|
||||
{
|
||||
glPolygonOffset(factor, units);
|
||||
|
||||
properties[GL_POLYGON_OFFSET_UNITS] = _units;
|
||||
properties[GL_POLYGON_OFFSET_FACTOR] = _factor;
|
||||
}
|
||||
}
|
||||
|
||||
void use_program(GLuint program)
|
||||
{
|
||||
if (current_program == program)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
current_program = program;
|
||||
glUseProgram(program);
|
||||
}
|
||||
|
||||
void bind_texture(GLuint layer, GLenum target, GLuint name)
|
||||
{
|
||||
ensure(layer < 48);
|
||||
|
||||
auto& bound = bound_textures[layer][target];
|
||||
if (bound != name)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + layer);
|
||||
glBindTexture(target, name);
|
||||
|
||||
bound = name;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class command_context
|
||||
{
|
||||
driver_state* drv;
|
||||
|
||||
public:
|
||||
command_context()
|
||||
: drv(nullptr)
|
||||
{}
|
||||
|
||||
command_context(driver_state& drv_)
|
||||
: drv(&drv_)
|
||||
{}
|
||||
|
||||
driver_state* operator -> () {
|
||||
return drv;
|
||||
}
|
||||
};
|
||||
|
||||
void set_command_context(gl::command_context& ctx);
|
||||
void set_command_context(gl::driver_state& ctx);
|
||||
gl::command_context get_command_context();
|
||||
|
||||
void set_primary_context_thread(bool = true);
|
||||
bool is_primary_context_thread();
|
||||
}
|
@ -52,7 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Emu\RSX\GL\GLCompute.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLExecutionState.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLOverlays.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLPipelineCompiler.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLTextOut.h" />
|
||||
@ -64,7 +63,10 @@
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\buffer_object.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\capabilities.hpp" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\common.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\pixel_settings.hpp" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\ring_buffer.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\state_tracker.hpp" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\image.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLVertexProgram.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLHelpers.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLRenderTargets.h" />
|
||||
@ -82,7 +84,9 @@
|
||||
<ClCompile Include="Emu\RSX\GL\GLOverlays.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\GLPipelineCompiler.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\buffer_object.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\common.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\ring_buffer.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\image.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\GLVertexProgram.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\GLHelpers.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\GLPresent.cpp" />
|
||||
|
@ -23,6 +23,12 @@
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\ring_buffer.cpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\image.cpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\common.cpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Emu\RSX\GL\GLTexture.h" />
|
||||
@ -39,7 +45,6 @@
|
||||
<ClInclude Include="Emu\RSX\GL\GLShaderInterpreter.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLTextOut.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLOverlays.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLExecutionState.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLCompute.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLPipelineCompiler.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\buffer_object.h">
|
||||
@ -54,6 +59,15 @@
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\capabilities.hpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\image.h">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\state_tracker.hpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\pixel_settings.hpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="glutils">
|
||||
|
Loading…
x
Reference in New Issue
Block a user