mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
gl: Refactor the rest of GLHelpers
This commit is contained in:
parent
09824a718f
commit
35ef19cfc8
@ -700,6 +700,12 @@ template<typename T>
|
||||
struct size3_base
|
||||
{
|
||||
T width, height, depth;
|
||||
|
||||
template<typename NT>
|
||||
explicit constexpr operator size3_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(width), static_cast<NT>(height), static_cast<NT>(depth) };
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "Emu/IdManager.h"
|
||||
#include "GLHelpers.h"
|
||||
#include "glutils/program.h"
|
||||
#include "../rsx_utils.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "../Program/FragmentProgramDecompiler.h"
|
||||
#include "../Program/GLSLTypes.h"
|
||||
#include "GLHelpers.h"
|
||||
#include "glutils/program.h"
|
||||
|
||||
namespace glsl
|
||||
{
|
||||
|
@ -10,9 +10,7 @@
|
||||
namespace gl
|
||||
{
|
||||
std::unordered_map<u32, std::unique_ptr<gl::compute_task>> g_compute_tasks;
|
||||
blitter *g_hw_blitter = nullptr;
|
||||
capabilities g_driver_caps;
|
||||
const fbo screen{};
|
||||
|
||||
void flush_command_queue(fence& fence_obj)
|
||||
{
|
||||
@ -171,271 +169,6 @@ namespace gl
|
||||
return g_driver_caps;
|
||||
}
|
||||
|
||||
void fbo::create()
|
||||
{
|
||||
glGenFramebuffers(1, &m_id);
|
||||
}
|
||||
|
||||
void fbo::bind() const
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
|
||||
}
|
||||
|
||||
void fbo::blit(const fbo& dst, areai src_area, areai dst_area, buffers buffers_, filter filter_) const
|
||||
{
|
||||
bind_as(target::read_frame_buffer);
|
||||
dst.bind_as(target::draw_frame_buffer);
|
||||
glBlitFramebuffer(
|
||||
src_area.x1, src_area.y1, src_area.x2, src_area.y2,
|
||||
dst_area.x1, dst_area.y1, dst_area.x2, dst_area.y2,
|
||||
static_cast<GLbitfield>(buffers_), static_cast<GLenum>(filter_));
|
||||
}
|
||||
|
||||
void fbo::bind_as(target target_) const
|
||||
{
|
||||
glBindFramebuffer(static_cast<int>(target_), id());
|
||||
}
|
||||
|
||||
void fbo::remove()
|
||||
{
|
||||
if (m_id != GL_NONE)
|
||||
{
|
||||
glDeleteFramebuffers(1, &m_id);
|
||||
m_id = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool fbo::created() const
|
||||
{
|
||||
return m_id != GL_NONE;
|
||||
}
|
||||
|
||||
bool fbo::check() const
|
||||
{
|
||||
GLenum status = DSA_CALL2_RET(CheckNamedFramebufferStatus, m_id, GL_FRAMEBUFFER);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
rsx_log.error("FBO check failed: 0x%04x", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fbo::recreate()
|
||||
{
|
||||
if (created())
|
||||
remove();
|
||||
|
||||
create();
|
||||
}
|
||||
|
||||
void fbo::draw_buffer(const attachment& buffer) const
|
||||
{
|
||||
GLenum buf = buffer.id();
|
||||
DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, 1, &buf);
|
||||
}
|
||||
|
||||
void fbo::draw_buffers(const std::initializer_list<attachment>& indexes) const
|
||||
{
|
||||
rsx::simple_array<GLenum> ids;
|
||||
ids.reserve(::size32(indexes));
|
||||
|
||||
for (auto &index : indexes)
|
||||
ids.push_back(index.id());
|
||||
|
||||
DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, static_cast<GLsizei>(ids.size()), ids.data());
|
||||
}
|
||||
|
||||
void fbo::read_buffer(const attachment& buffer) const
|
||||
{
|
||||
DSA_CALL3(NamedFramebufferReadBuffer, FramebufferReadBuffer, m_id, buffer.id());
|
||||
}
|
||||
|
||||
void fbo::draw_arrays(rsx::primitive_type mode, GLsizei count, GLint first) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
glDrawArrays(draw_mode(mode), first, count);
|
||||
}
|
||||
|
||||
void fbo::draw_arrays(const buffer& buffer, rsx::primitive_type mode, GLsizei count, GLint first) const
|
||||
{
|
||||
buffer.bind(buffer::target::array);
|
||||
draw_arrays(mode, count, first);
|
||||
}
|
||||
|
||||
void fbo::draw_arrays(const vao& buffer, rsx::primitive_type mode, GLsizei count, GLint first) const
|
||||
{
|
||||
buffer.bind();
|
||||
draw_arrays(mode, count, first);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
glDrawElements(draw_mode(mode), count, static_cast<GLenum>(type), indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const
|
||||
{
|
||||
buffer.bind(buffer::target::array);
|
||||
glDrawElements(draw_mode(mode), count, static_cast<GLenum>(type), indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset) const
|
||||
{
|
||||
indices.bind(buffer::target::element_array);
|
||||
glDrawElements(draw_mode(mode), count, static_cast<GLenum>(type), reinterpret_cast<GLvoid*>(indices_buffer_offset));
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer_, rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset) const
|
||||
{
|
||||
buffer_.bind(buffer::target::array);
|
||||
draw_elements(mode, count, type, indices, indices_buffer_offset);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const
|
||||
{
|
||||
draw_elements(mode, count, indices_type::ubyte, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const
|
||||
{
|
||||
draw_elements(buffer, mode, count, indices_type::ubyte, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, const GLushort *indices) const
|
||||
{
|
||||
draw_elements(mode, count, indices_type::ushort, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLushort *indices) const
|
||||
{
|
||||
draw_elements(buffer, mode, count, indices_type::ushort, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, const GLuint *indices) const
|
||||
{
|
||||
draw_elements(mode, count, indices_type::uint, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLuint *indices) const
|
||||
{
|
||||
draw_elements(buffer, mode, count, indices_type::uint, indices);
|
||||
}
|
||||
|
||||
void fbo::clear(buffers buffers_) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
glClear(static_cast<GLbitfield>(buffers_));
|
||||
}
|
||||
|
||||
void fbo::clear(buffers buffers_, color4f color_value, double depth_value, u8 stencil_value) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
glClearColor(color_value.r, color_value.g, color_value.b, color_value.a);
|
||||
glClearDepth(depth_value);
|
||||
glClearStencil(stencil_value);
|
||||
clear(buffers_);
|
||||
}
|
||||
|
||||
void fbo::copy_from(const void* pixels, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
pixel_settings.apply();
|
||||
glDrawPixels(size.width, size.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), pixels);
|
||||
}
|
||||
|
||||
void fbo::copy_from(const buffer& buf, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
buffer::save_binding_state save_buffer(buffer::target::pixel_unpack, buf);
|
||||
pixel_settings.apply();
|
||||
glDrawPixels(size.width, size.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), nullptr);
|
||||
}
|
||||
|
||||
void fbo::copy_to(void* pixels, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
pixel_settings.apply();
|
||||
glReadPixels(coord.x, coord.y, coord.width, coord.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), pixels);
|
||||
}
|
||||
|
||||
void fbo::copy_to(const buffer& buf, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
buffer::save_binding_state save_buffer(buffer::target::pixel_pack, buf);
|
||||
pixel_settings.apply();
|
||||
glReadPixels(coord.x, coord.y, coord.width, coord.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), nullptr);
|
||||
}
|
||||
|
||||
fbo fbo::get_bound_draw_buffer()
|
||||
{
|
||||
GLint value;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &value);
|
||||
|
||||
return{ static_cast<GLuint>(value) };
|
||||
}
|
||||
|
||||
fbo fbo::get_bound_read_buffer()
|
||||
{
|
||||
GLint value;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &value);
|
||||
|
||||
return{ static_cast<GLuint>(value) };
|
||||
}
|
||||
|
||||
fbo fbo::get_bound_buffer()
|
||||
{
|
||||
GLint value;
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value);
|
||||
|
||||
return{ static_cast<GLuint>(value) };
|
||||
}
|
||||
|
||||
GLuint fbo::id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void fbo::set_id(GLuint id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
void fbo::set_extents(const size2i& extents)
|
||||
{
|
||||
m_size = extents;
|
||||
}
|
||||
|
||||
size2i fbo::get_extents() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool fbo::matches(const std::array<GLuint, 4>& color_targets, GLuint depth_stencil_target) const
|
||||
{
|
||||
for (u32 index = 0; index < 4; ++index)
|
||||
{
|
||||
if (color[index].resource_id() != color_targets[index])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const auto depth_resource = depth.resource_id() | depth_stencil.resource_id();
|
||||
return (depth_resource == depth_stencil_target);
|
||||
}
|
||||
|
||||
bool fbo::references_any(const std::vector<GLuint>& resources) const
|
||||
{
|
||||
return std::any_of(m_resource_bindings.cbegin(), m_resource_bindings.cend(), [&resources](const auto& e)
|
||||
{
|
||||
return std::find(resources.cbegin(), resources.cend(), e.second) != resources.cend();
|
||||
});
|
||||
}
|
||||
|
||||
bool is_primitive_native(rsx::primitive_type in)
|
||||
{
|
||||
switch (in)
|
||||
@ -456,201 +189,4 @@ namespace gl
|
||||
fmt::throw_exception("unknown primitive type");
|
||||
}
|
||||
}
|
||||
|
||||
attrib_t vao::operator[](u32 index) const noexcept
|
||||
{
|
||||
return attrib_t(index);
|
||||
}
|
||||
|
||||
void blitter::scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect,
|
||||
bool linear_interpolation, const rsx::typeless_xfer& xfer_info)
|
||||
{
|
||||
std::unique_ptr<texture> typeless_src;
|
||||
std::unique_ptr<texture> typeless_dst;
|
||||
const gl::texture* real_src = src;
|
||||
const gl::texture* real_dst = dst;
|
||||
|
||||
// Optimization pass; check for pass-through data transfer
|
||||
if (!xfer_info.flip_horizontal && !xfer_info.flip_vertical && src_rect.height() == dst_rect.height())
|
||||
{
|
||||
auto src_w = src_rect.width();
|
||||
auto dst_w = dst_rect.width();
|
||||
|
||||
if (xfer_info.src_is_typeless) src_w = static_cast<int>(src_w * xfer_info.src_scaling_hint);
|
||||
if (xfer_info.dst_is_typeless) dst_w = static_cast<int>(dst_w * xfer_info.dst_scaling_hint);
|
||||
|
||||
if (src_w == dst_w)
|
||||
{
|
||||
// Final dimensions are a match
|
||||
if (xfer_info.src_is_typeless || xfer_info.dst_is_typeless)
|
||||
{
|
||||
const coord3i src_region = { { src_rect.x1, src_rect.y1, 0 }, { src_rect.width(), src_rect.height(), 1 } };
|
||||
const coord3i dst_region = { { dst_rect.x1, dst_rect.y1, 0 }, { dst_rect.width(), dst_rect.height(), 1 } };
|
||||
gl::copy_typeless(cmd, dst, src, static_cast<coord3u>(dst_region), static_cast<coord3u>(src_region));
|
||||
}
|
||||
else
|
||||
{
|
||||
glCopyImageSubData(src->id(), GL_TEXTURE_2D, 0, src_rect.x1, src_rect.y1, 0,
|
||||
dst->id(), GL_TEXTURE_2D, 0, dst_rect.x1, dst_rect.y1, 0,
|
||||
src_rect.width(), src_rect.height(), 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (xfer_info.src_is_typeless)
|
||||
{
|
||||
const auto internal_fmt = xfer_info.src_native_format_override ?
|
||||
GLenum(xfer_info.src_native_format_override) :
|
||||
get_sized_internal_format(xfer_info.src_gcm_format);
|
||||
|
||||
if (static_cast<gl::texture::internal_format>(internal_fmt) != src->get_internal_format())
|
||||
{
|
||||
const u16 internal_width = static_cast<u16>(src->width() * xfer_info.src_scaling_hint);
|
||||
typeless_src = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, internal_fmt);
|
||||
copy_typeless(cmd, typeless_src.get(), src);
|
||||
|
||||
real_src = typeless_src.get();
|
||||
src_rect.x1 = static_cast<u16>(src_rect.x1 * xfer_info.src_scaling_hint);
|
||||
src_rect.x2 = static_cast<u16>(src_rect.x2 * xfer_info.src_scaling_hint);
|
||||
}
|
||||
}
|
||||
|
||||
if (xfer_info.dst_is_typeless)
|
||||
{
|
||||
const auto internal_fmt = xfer_info.dst_native_format_override ?
|
||||
GLenum(xfer_info.dst_native_format_override) :
|
||||
get_sized_internal_format(xfer_info.dst_gcm_format);
|
||||
|
||||
if (static_cast<gl::texture::internal_format>(internal_fmt) != dst->get_internal_format())
|
||||
{
|
||||
const auto internal_width = static_cast<u16>(dst->width() * xfer_info.dst_scaling_hint);
|
||||
typeless_dst = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, internal_fmt);
|
||||
copy_typeless(cmd, typeless_dst.get(), dst);
|
||||
|
||||
real_dst = typeless_dst.get();
|
||||
dst_rect.x1 = static_cast<u16>(dst_rect.x1 * xfer_info.dst_scaling_hint);
|
||||
dst_rect.x2 = static_cast<u16>(dst_rect.x2 * xfer_info.dst_scaling_hint);
|
||||
}
|
||||
}
|
||||
|
||||
ensure(real_src->aspect() == real_dst->aspect());
|
||||
|
||||
if (src_rect.width() == dst_rect.width() && src_rect.height() == dst_rect.height() &&
|
||||
!src_rect.is_flipped() && !dst_rect.is_flipped())
|
||||
{
|
||||
glCopyImageSubData(real_src->id(), static_cast<GLenum>(real_src->get_target()), 0, src_rect.x1, src_rect.y1, 0,
|
||||
real_dst->id(), static_cast<GLenum>(real_dst->get_target()), 0, dst_rect.x1, dst_rect.y1, 0,
|
||||
src_rect.width(), src_rect.height(), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool is_depth_copy = (real_src->aspect() != image_aspect::color);
|
||||
const filter interp = (linear_interpolation && !is_depth_copy) ? filter::linear : filter::nearest;
|
||||
gl::fbo::attachment::type attachment;
|
||||
gl::buffers target;
|
||||
|
||||
if (is_depth_copy)
|
||||
{
|
||||
if (real_dst->aspect() & gl::image_aspect::stencil)
|
||||
{
|
||||
attachment = fbo::attachment::type::depth_stencil;
|
||||
target = gl::buffers::depth_stencil;
|
||||
}
|
||||
else
|
||||
{
|
||||
attachment = fbo::attachment::type::depth;
|
||||
target = gl::buffers::depth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attachment = fbo::attachment::type::color;
|
||||
target = gl::buffers::color;
|
||||
}
|
||||
|
||||
cmd->disable(GL_SCISSOR_TEST);
|
||||
|
||||
save_binding_state saved;
|
||||
|
||||
gl::fbo::attachment src_att{blit_src, static_cast<fbo::attachment::type>(attachment)};
|
||||
src_att = *real_src;
|
||||
|
||||
gl::fbo::attachment dst_att{ blit_dst, static_cast<fbo::attachment::type>(attachment) };
|
||||
dst_att = *real_dst;
|
||||
|
||||
if (xfer_info.flip_horizontal)
|
||||
{
|
||||
src_rect.flip_horizontal();
|
||||
}
|
||||
|
||||
if (xfer_info.flip_vertical)
|
||||
{
|
||||
src_rect.flip_vertical();
|
||||
}
|
||||
|
||||
blit_src.blit(blit_dst, src_rect, dst_rect, target, interp);
|
||||
|
||||
// Release the attachments explicitly (not doing so causes glitches, e.g Journey Menu)
|
||||
src_att = GL_NONE;
|
||||
dst_att = GL_NONE;
|
||||
}
|
||||
|
||||
if (xfer_info.dst_is_typeless)
|
||||
{
|
||||
// Transfer contents from typeless dst back to original dst
|
||||
copy_typeless(cmd, dst, typeless_dst.get());
|
||||
}
|
||||
}
|
||||
|
||||
void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, const color4f& color)
|
||||
{
|
||||
save_binding_state saved;
|
||||
|
||||
blit_dst.bind();
|
||||
blit_dst.color[0] = *dst;
|
||||
blit_dst.check();
|
||||
|
||||
cmd->clear_color(color);
|
||||
cmd->color_maski(0, true, true, true, true);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
blit_dst.color[0] = GL_NONE;
|
||||
}
|
||||
|
||||
void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, float /*depth*/, u8 /*stencil*/)
|
||||
{
|
||||
fbo::attachment::type attachment;
|
||||
GLbitfield clear_mask;
|
||||
|
||||
switch (const auto fmt = dst->get_internal_format())
|
||||
{
|
||||
case texture::internal_format::depth16:
|
||||
case texture::internal_format::depth32f:
|
||||
clear_mask = GL_DEPTH_BUFFER_BIT;
|
||||
attachment = fbo::attachment::type::depth;
|
||||
break;
|
||||
case texture::internal_format::depth24_stencil8:
|
||||
case texture::internal_format::depth32f_stencil8:
|
||||
clear_mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||
attachment = fbo::attachment::type::depth_stencil;
|
||||
break;
|
||||
default:
|
||||
fmt::throw_exception("Invalid texture passed to clear depth function, format=0x%x", static_cast<u32>(fmt));
|
||||
}
|
||||
|
||||
save_binding_state saved;
|
||||
fbo::attachment attach_point{ blit_dst, attachment };
|
||||
|
||||
blit_dst.bind();
|
||||
attach_point = *dst;
|
||||
blit_dst.check();
|
||||
|
||||
cmd->depth_mask(GL_TRUE);
|
||||
cmd->stencil_mask(0xFF);
|
||||
|
||||
glClear(clear_mask);
|
||||
attach_point = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,11 @@
|
||||
#include "../Common/simple_array.hpp"
|
||||
#include "../Overlays/overlays.h"
|
||||
#include "GLTexture.h"
|
||||
|
||||
#include "glutils/fbo.h"
|
||||
#include "glutils/program.h"
|
||||
#include "glutils/vao.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
@ -115,6 +120,16 @@ namespace gl
|
||||
void run(gl::command_context& cmd, const buffer* src, const texture* dst, const u32 src_offset, const coordu& dst_region, const pixel_unpack_settings& settings);
|
||||
};
|
||||
|
||||
struct rp_copy_rgba_to_bgra : public overlay_pass
|
||||
{
|
||||
void run(gl::command_context& cmd, const texture* src, const texture* dst, const coordu& src_region, const coordu& dst_region);
|
||||
};
|
||||
|
||||
struct rp_copy_bgra_to_rgba : public overlay_pass
|
||||
{
|
||||
void run(gl::command_context& cmd, const texture* src, const texture* dst, const coordu& src_region, const coordu& dst_region);
|
||||
};
|
||||
|
||||
// TODO: Replace with a proper manager
|
||||
extern std::unordered_map<u32, std::unique_ptr<gl::overlay_pass>> g_overlay_passes;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "GLHelpers.h"
|
||||
#include "glutils/program.h"
|
||||
#include "Emu/RSX/display.h"
|
||||
#include "Utilities/lockless.h"
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "GLHelpers.h"
|
||||
#include "../rsx_utils.h"
|
||||
|
||||
#include "glutils/fbo.h"
|
||||
|
||||
struct color_swizzle
|
||||
{
|
||||
gl::texture::channel a = gl::texture::channel::a;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "GLHelpers.h"
|
||||
#include "glutils/program.h"
|
||||
#include "../Program/ProgramStateCache.h"
|
||||
#include "../Common/TextureUtils.h"
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "GLHelpers.h"
|
||||
#include "glutils/vao.hpp"
|
||||
#include "../Common/TextGlyphs.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
|
||||
#include "GLRenderTargets.h"
|
||||
#include "glutils/blitter.h"
|
||||
#include "glutils/sync.hpp"
|
||||
|
||||
#include "../Common/texture_cache.h"
|
||||
|
||||
#include <memory>
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "../Program/VertexProgramDecompiler.h"
|
||||
#include "GLHelpers.h"
|
||||
#include "glutils/program.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
|
268
rpcs3/Emu/RSX/GL/glutils/blitter.cpp
Normal file
268
rpcs3/Emu/RSX/GL/glutils/blitter.cpp
Normal file
@ -0,0 +1,268 @@
|
||||
#include "stdafx.h"
|
||||
#include "blitter.h"
|
||||
#include "state_tracker.hpp"
|
||||
|
||||
#include "../GLTexture.h" // TODO: This system also needs to be refactored
|
||||
#include "../GLOverlays.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
static blitter* g_hw_blitter = nullptr;
|
||||
|
||||
void process_bgra_transfer_source(const gl::texture* src, const gl::texture* dst, const coord3i& region)
|
||||
{
|
||||
ensure(src->get_internal_format() == texture::internal_format::bgra8);
|
||||
ensure(dst->get_internal_format() == texture::internal_format::rgba8);
|
||||
}
|
||||
|
||||
void process_bgra_transfer_dest(const gl::texture* tex, const coord3i& region)
|
||||
{
|
||||
ensure(tex->get_internal_format() == texture::internal_format::bgra8);
|
||||
}
|
||||
|
||||
void blitter::copy_image(gl::command_context& cmd, const texture* src, const texture* dst, int src_level, int dst_level, const position3i& src_offset, const position3i& dst_offset, const size3i& size) const
|
||||
{
|
||||
ensure(src_level == 0);
|
||||
|
||||
// Typeless bypass for BGRA8
|
||||
std::unique_ptr<gl::texture> temp_image;
|
||||
const texture* real_src = src;
|
||||
bool handle_bgra8_dest = false;
|
||||
|
||||
if (src->get_internal_format() != dst->get_internal_format())
|
||||
{
|
||||
if (false && src->get_internal_format() == texture::internal_format::bgra8)
|
||||
{
|
||||
temp_image = std::make_unique<texture>(static_cast<GLenum>(src->get_target()), src->width(), src->height(), src->depth(), src->levels(), GL_RGBA8, rsx::format_class::RSX_FORMAT_CLASS_COLOR);
|
||||
process_bgra_transfer_source(src, temp_image.get(), { src_offset, size });
|
||||
real_src = temp_image.get();
|
||||
}
|
||||
|
||||
handle_bgra8_dest = (dst->get_internal_format() == texture::internal_format::bgra8);
|
||||
}
|
||||
|
||||
glCopyImageSubData(real_src->id(), static_cast<GLenum>(real_src->get_target()), src_level,
|
||||
src_offset.x, src_offset.y, src_offset.z,
|
||||
dst->id(), static_cast<GLenum>(dst->get_target()), dst_level,
|
||||
dst_offset.x, dst_offset.y, dst_offset.z, size.width, size.height, size.depth);
|
||||
|
||||
if (handle_bgra8_dest)
|
||||
{
|
||||
process_bgra_transfer_dest(dst, { dst_offset, size });
|
||||
}
|
||||
}
|
||||
|
||||
void blitter::scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect,
|
||||
bool linear_interpolation, const rsx::typeless_xfer& xfer_info)
|
||||
{
|
||||
std::unique_ptr<texture> typeless_src;
|
||||
std::unique_ptr<texture> typeless_dst;
|
||||
const gl::texture* real_src = src;
|
||||
const gl::texture* real_dst = dst;
|
||||
|
||||
// Optimization pass; check for pass-through data transfer
|
||||
if (!xfer_info.flip_horizontal && !xfer_info.flip_vertical && src_rect.height() == dst_rect.height())
|
||||
{
|
||||
auto src_w = src_rect.width();
|
||||
auto dst_w = dst_rect.width();
|
||||
|
||||
if (xfer_info.src_is_typeless) src_w = static_cast<int>(src_w * xfer_info.src_scaling_hint);
|
||||
if (xfer_info.dst_is_typeless) dst_w = static_cast<int>(dst_w * xfer_info.dst_scaling_hint);
|
||||
|
||||
if (src_w == dst_w)
|
||||
{
|
||||
// Final dimensions are a match
|
||||
if (xfer_info.src_is_typeless || xfer_info.dst_is_typeless)
|
||||
{
|
||||
const coord3i src_region = { { src_rect.x1, src_rect.y1, 0 }, { src_rect.width(), src_rect.height(), 1 } };
|
||||
const coord3i dst_region = { { dst_rect.x1, dst_rect.y1, 0 }, { dst_rect.width(), dst_rect.height(), 1 } };
|
||||
gl::copy_typeless(cmd, dst, src, static_cast<coord3u>(dst_region), static_cast<coord3u>(src_region));
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_image(cmd, src, dst, 0, 1, { src_rect.x1, src_rect.y1, 0u }, { dst_rect.x1, dst_rect.y1, 0 }, { src_rect.width(), src_rect.height(), 1 });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (xfer_info.src_is_typeless)
|
||||
{
|
||||
const auto internal_fmt = xfer_info.src_native_format_override ?
|
||||
GLenum(xfer_info.src_native_format_override) :
|
||||
get_sized_internal_format(xfer_info.src_gcm_format);
|
||||
|
||||
if (static_cast<gl::texture::internal_format>(internal_fmt) != src->get_internal_format())
|
||||
{
|
||||
const u16 internal_width = static_cast<u16>(src->width() * xfer_info.src_scaling_hint);
|
||||
typeless_src = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, internal_fmt);
|
||||
copy_typeless(cmd, typeless_src.get(), src);
|
||||
|
||||
real_src = typeless_src.get();
|
||||
src_rect.x1 = static_cast<u16>(src_rect.x1 * xfer_info.src_scaling_hint);
|
||||
src_rect.x2 = static_cast<u16>(src_rect.x2 * xfer_info.src_scaling_hint);
|
||||
}
|
||||
}
|
||||
|
||||
if (xfer_info.dst_is_typeless)
|
||||
{
|
||||
const auto internal_fmt = xfer_info.dst_native_format_override ?
|
||||
GLenum(xfer_info.dst_native_format_override) :
|
||||
get_sized_internal_format(xfer_info.dst_gcm_format);
|
||||
|
||||
if (static_cast<gl::texture::internal_format>(internal_fmt) != dst->get_internal_format())
|
||||
{
|
||||
const auto internal_width = static_cast<u16>(dst->width() * xfer_info.dst_scaling_hint);
|
||||
typeless_dst = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, internal_fmt);
|
||||
copy_typeless(cmd, typeless_dst.get(), dst);
|
||||
|
||||
real_dst = typeless_dst.get();
|
||||
dst_rect.x1 = static_cast<u16>(dst_rect.x1 * xfer_info.dst_scaling_hint);
|
||||
dst_rect.x2 = static_cast<u16>(dst_rect.x2 * xfer_info.dst_scaling_hint);
|
||||
}
|
||||
}
|
||||
|
||||
if (src->get_internal_format() == texture::internal_format::bgra8 &&
|
||||
real_src == src &&
|
||||
dst->get_internal_format() != src->get_internal_format())
|
||||
{
|
||||
// Not typeless, plus src is bgra8. Needs conversion
|
||||
typeless_src = std::make_unique<texture>(GL_TEXTURE_2D, src->width(), src->height(), 1, 1, GL_RGBA8);
|
||||
process_bgra_transfer_source(src, typeless_src.get(), {{src_rect.x1, src_rect.y1, 0}, {src_rect.width(), src_rect.height(), 1}});
|
||||
real_src = typeless_src.get();
|
||||
}
|
||||
|
||||
bool handle_bgra8_dest = false;
|
||||
if (dst->get_internal_format() == texture::internal_format::bgra8 &&
|
||||
real_dst == dst &&
|
||||
dst->get_internal_format() != src->get_internal_format())
|
||||
{
|
||||
// Not typeless but dst is bgra8.
|
||||
// Handle the conversion in post
|
||||
handle_bgra8_dest = true;
|
||||
}
|
||||
|
||||
ensure(real_src->aspect() == real_dst->aspect());
|
||||
|
||||
if (src_rect.width() == dst_rect.width() && src_rect.height() == dst_rect.height() &&
|
||||
!src_rect.is_flipped() && !dst_rect.is_flipped())
|
||||
{
|
||||
copy_image(cmd, real_src, real_dst, 0, 1, { src_rect.x1, src_rect.y1, 0 }, { dst_rect.x1, dst_rect.y1, 0 }, { src_rect.width(), src_rect.height(), 1 });
|
||||
handle_bgra8_dest = false; // Handled in copy_image
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool is_depth_copy = (real_src->aspect() != image_aspect::color);
|
||||
const filter interp = (linear_interpolation && !is_depth_copy) ? filter::linear : filter::nearest;
|
||||
gl::fbo::attachment::type attachment;
|
||||
gl::buffers target;
|
||||
|
||||
if (is_depth_copy)
|
||||
{
|
||||
if (real_dst->aspect() & gl::image_aspect::stencil)
|
||||
{
|
||||
attachment = fbo::attachment::type::depth_stencil;
|
||||
target = gl::buffers::depth_stencil;
|
||||
}
|
||||
else
|
||||
{
|
||||
attachment = fbo::attachment::type::depth;
|
||||
target = gl::buffers::depth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attachment = fbo::attachment::type::color;
|
||||
target = gl::buffers::color;
|
||||
}
|
||||
|
||||
cmd->disable(GL_SCISSOR_TEST);
|
||||
|
||||
save_binding_state saved;
|
||||
|
||||
gl::fbo::attachment src_att{ blit_src, static_cast<fbo::attachment::type>(attachment) };
|
||||
src_att = *real_src;
|
||||
|
||||
gl::fbo::attachment dst_att{ blit_dst, static_cast<fbo::attachment::type>(attachment) };
|
||||
dst_att = *real_dst;
|
||||
|
||||
if (xfer_info.flip_horizontal)
|
||||
{
|
||||
src_rect.flip_horizontal();
|
||||
}
|
||||
|
||||
if (xfer_info.flip_vertical)
|
||||
{
|
||||
src_rect.flip_vertical();
|
||||
}
|
||||
|
||||
blit_src.blit(blit_dst, src_rect, dst_rect, target, interp);
|
||||
|
||||
// Release the attachments explicitly (not doing so causes glitches, e.g Journey Menu)
|
||||
src_att = GL_NONE;
|
||||
dst_att = GL_NONE;
|
||||
}
|
||||
|
||||
if (xfer_info.dst_is_typeless)
|
||||
{
|
||||
// Transfer contents from typeless dst back to original dst
|
||||
copy_typeless(cmd, dst, typeless_dst.get());
|
||||
}
|
||||
else if (handle_bgra8_dest)
|
||||
{
|
||||
// Blit transfer to BGRA8 target
|
||||
process_bgra_transfer_dest(dst, { {dst_rect.x1, dst_rect.y1, 0}, {dst_rect.width(), dst_rect.height(), 1} });
|
||||
}
|
||||
}
|
||||
|
||||
void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, const color4f& color)
|
||||
{
|
||||
save_binding_state saved;
|
||||
|
||||
blit_dst.bind();
|
||||
blit_dst.color[0] = *dst;
|
||||
blit_dst.check();
|
||||
|
||||
cmd->clear_color(color);
|
||||
cmd->color_maski(0, true, true, true, true);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
blit_dst.color[0] = GL_NONE;
|
||||
}
|
||||
|
||||
void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, float /*depth*/, u8 /*stencil*/)
|
||||
{
|
||||
fbo::attachment::type attachment;
|
||||
GLbitfield clear_mask;
|
||||
|
||||
switch (const auto fmt = dst->get_internal_format())
|
||||
{
|
||||
case texture::internal_format::depth16:
|
||||
case texture::internal_format::depth32f:
|
||||
clear_mask = GL_DEPTH_BUFFER_BIT;
|
||||
attachment = fbo::attachment::type::depth;
|
||||
break;
|
||||
case texture::internal_format::depth24_stencil8:
|
||||
case texture::internal_format::depth32f_stencil8:
|
||||
clear_mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||
attachment = fbo::attachment::type::depth_stencil;
|
||||
break;
|
||||
default:
|
||||
fmt::throw_exception("Invalid texture passed to clear depth function, format=0x%x", static_cast<u32>(fmt));
|
||||
}
|
||||
|
||||
save_binding_state saved;
|
||||
fbo::attachment attach_point{ blit_dst, attachment };
|
||||
|
||||
blit_dst.bind();
|
||||
attach_point = *dst;
|
||||
blit_dst.check();
|
||||
|
||||
cmd->depth_mask(GL_TRUE);
|
||||
cmd->stencil_mask(0xFF);
|
||||
|
||||
glClear(clear_mask);
|
||||
attach_point = GL_NONE;
|
||||
}
|
||||
}
|
58
rpcs3/Emu/RSX/GL/glutils/blitter.h
Normal file
58
rpcs3/Emu/RSX/GL/glutils/blitter.h
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "fbo.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
class command_context;
|
||||
class texture;
|
||||
|
||||
class blitter
|
||||
{
|
||||
struct save_binding_state
|
||||
{
|
||||
GLuint old_fbo;
|
||||
|
||||
save_binding_state()
|
||||
{
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, reinterpret_cast<GLint*>(&old_fbo));
|
||||
}
|
||||
|
||||
~save_binding_state()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
|
||||
}
|
||||
};
|
||||
|
||||
fbo blit_src;
|
||||
fbo blit_dst;
|
||||
|
||||
public:
|
||||
|
||||
void init()
|
||||
{
|
||||
blit_src.create();
|
||||
blit_dst.create();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
blit_dst.remove();
|
||||
blit_src.remove();
|
||||
}
|
||||
|
||||
void scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect, bool linear_interpolation,
|
||||
const rsx::typeless_xfer& xfer_info);
|
||||
|
||||
void copy_image(gl::command_context& cmd, const texture* src, const texture* dst, int src_level, int dst_level, const position3i& src_offset, const position3i& dst_offset, const size3i& size) const;
|
||||
|
||||
void fast_clear_image(gl::command_context& cmd, const texture* dst, const color4f& color);
|
||||
void fast_clear_image(gl::command_context& cmd, const texture* dst, float depth, u8 stencil);
|
||||
|
||||
void copy_image(gl::command_context& cmd, const texture* src, const texture* dst, int src_level, int dst_level, const position3u& src_offset, const position3u& dst_offset, const size3u& size) const
|
||||
{
|
||||
copy_image(cmd, src, dst, src_level, dst_level, static_cast<position3i>(src_offset), static_cast<position3i>(dst_offset), static_cast<size3i>(size));
|
||||
}
|
||||
};
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "state_tracker.hpp"
|
||||
#include "vao.hpp"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
@ -30,4 +31,9 @@ namespace gl
|
||||
{
|
||||
return { *s_current_state };
|
||||
}
|
||||
|
||||
attrib_t vao::operator[](u32 index) const noexcept
|
||||
{
|
||||
return attrib_t(index);
|
||||
}
|
||||
}
|
||||
|
@ -48,127 +48,25 @@
|
||||
|
||||
namespace gl
|
||||
{
|
||||
// TODO: Move to sync.h
|
||||
class fence
|
||||
template<typename Type, uint BindId, uint GetStateId>
|
||||
class save_binding_state_base
|
||||
{
|
||||
GLsync m_value = nullptr;
|
||||
mutable GLenum flags = GL_SYNC_FLUSH_COMMANDS_BIT;
|
||||
mutable bool signaled = false;
|
||||
GLint m_last_binding;
|
||||
|
||||
public:
|
||||
|
||||
fence() = default;
|
||||
~fence() = default;
|
||||
|
||||
void create()
|
||||
save_binding_state_base(const Type& new_state) : save_binding_state_base()
|
||||
{
|
||||
m_value = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
flags = GL_SYNC_FLUSH_COMMANDS_BIT;
|
||||
new_state.bind();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
save_binding_state_base()
|
||||
{
|
||||
glDeleteSync(m_value);
|
||||
m_value = nullptr;
|
||||
glGetIntegerv(GetStateId, &m_last_binding);
|
||||
}
|
||||
|
||||
void reset()
|
||||
~save_binding_state_base()
|
||||
{
|
||||
if (m_value != nullptr)
|
||||
destroy();
|
||||
|
||||
create();
|
||||
}
|
||||
|
||||
bool is_empty() const
|
||||
{
|
||||
return (m_value == nullptr);
|
||||
}
|
||||
|
||||
bool check_signaled() const
|
||||
{
|
||||
ensure(m_value);
|
||||
|
||||
if (signaled)
|
||||
return true;
|
||||
|
||||
if (flags)
|
||||
{
|
||||
GLenum err = glClientWaitSync(m_value, flags, 0);
|
||||
flags = 0;
|
||||
|
||||
if (!(err == GL_ALREADY_SIGNALED || err == GL_CONDITION_SATISFIED))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
GLint status = GL_UNSIGNALED;
|
||||
GLint tmp;
|
||||
|
||||
glGetSynciv(m_value, GL_SYNC_STATUS, 4, &tmp, &status);
|
||||
|
||||
if (status != GL_SIGNALED)
|
||||
return false;
|
||||
}
|
||||
|
||||
signaled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wait_for_signal()
|
||||
{
|
||||
ensure(m_value);
|
||||
|
||||
if (signaled == GL_FALSE)
|
||||
{
|
||||
GLenum err = GL_WAIT_FAILED;
|
||||
bool done = false;
|
||||
|
||||
while (!done)
|
||||
{
|
||||
if (flags)
|
||||
{
|
||||
err = glClientWaitSync(m_value, flags, 0);
|
||||
flags = 0;
|
||||
|
||||
switch (err)
|
||||
{
|
||||
default:
|
||||
rsx_log.error("gl::fence sync returned unknown error 0x%X", err);
|
||||
[[fallthrough]];
|
||||
case GL_ALREADY_SIGNALED:
|
||||
case GL_CONDITION_SATISFIED:
|
||||
done = true;
|
||||
break;
|
||||
case GL_TIMEOUT_EXPIRED:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GLint status = GL_UNSIGNALED;
|
||||
GLint tmp;
|
||||
|
||||
glGetSynciv(m_value, GL_SYNC_STATUS, 4, &tmp, &status);
|
||||
|
||||
if (status == GL_SIGNALED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
signaled = (err == GL_ALREADY_SIGNALED || err == GL_CONDITION_SATISFIED);
|
||||
}
|
||||
|
||||
glDeleteSync(m_value);
|
||||
m_value = nullptr;
|
||||
|
||||
return signaled;
|
||||
}
|
||||
|
||||
void server_wait_sync() const
|
||||
{
|
||||
ensure(m_value != nullptr);
|
||||
glWaitSync(m_value, 0, GL_TIMEOUT_IGNORED);
|
||||
glBindBuffer(BindId, m_last_binding);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
276
rpcs3/Emu/RSX/GL/glutils/fbo.cpp
Normal file
276
rpcs3/Emu/RSX/GL/glutils/fbo.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
#include "stdafx.h"
|
||||
#include "fbo.h"
|
||||
#include "buffer_object.h"
|
||||
#include "vao.hpp"
|
||||
|
||||
#include "Emu/RSX/Common/simple_array.hpp"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
const fbo screen{};
|
||||
|
||||
void fbo::create()
|
||||
{
|
||||
glGenFramebuffers(1, &m_id);
|
||||
}
|
||||
|
||||
void fbo::bind() const
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_id);
|
||||
}
|
||||
|
||||
void fbo::blit(const fbo& dst, areai src_area, areai dst_area, buffers buffers_, filter filter_) const
|
||||
{
|
||||
bind_as(target::read_frame_buffer);
|
||||
dst.bind_as(target::draw_frame_buffer);
|
||||
glBlitFramebuffer(
|
||||
src_area.x1, src_area.y1, src_area.x2, src_area.y2,
|
||||
dst_area.x1, dst_area.y1, dst_area.x2, dst_area.y2,
|
||||
static_cast<GLbitfield>(buffers_), static_cast<GLenum>(filter_));
|
||||
}
|
||||
|
||||
void fbo::bind_as(target target_) const
|
||||
{
|
||||
glBindFramebuffer(static_cast<int>(target_), id());
|
||||
}
|
||||
|
||||
void fbo::remove()
|
||||
{
|
||||
if (m_id != GL_NONE)
|
||||
{
|
||||
glDeleteFramebuffers(1, &m_id);
|
||||
m_id = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool fbo::created() const
|
||||
{
|
||||
return m_id != GL_NONE;
|
||||
}
|
||||
|
||||
bool fbo::check() const
|
||||
{
|
||||
GLenum status = DSA_CALL2_RET(CheckNamedFramebufferStatus, m_id, GL_FRAMEBUFFER);
|
||||
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
rsx_log.error("FBO check failed: 0x%04x", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fbo::recreate()
|
||||
{
|
||||
if (created())
|
||||
remove();
|
||||
|
||||
create();
|
||||
}
|
||||
|
||||
void fbo::draw_buffer(const attachment& buffer) const
|
||||
{
|
||||
GLenum buf = buffer.id();
|
||||
DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, 1, &buf);
|
||||
}
|
||||
|
||||
void fbo::draw_buffers(const std::initializer_list<attachment>& indexes) const
|
||||
{
|
||||
rsx::simple_array<GLenum> ids;
|
||||
ids.reserve(::size32(indexes));
|
||||
|
||||
for (auto& index : indexes)
|
||||
ids.push_back(index.id());
|
||||
|
||||
DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, static_cast<GLsizei>(ids.size()), ids.data());
|
||||
}
|
||||
|
||||
void fbo::read_buffer(const attachment& buffer) const
|
||||
{
|
||||
DSA_CALL3(NamedFramebufferReadBuffer, FramebufferReadBuffer, m_id, buffer.id());
|
||||
}
|
||||
|
||||
void fbo::draw_arrays(GLenum mode, GLsizei count, GLint first) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
glDrawArrays(mode, first, count);
|
||||
}
|
||||
|
||||
void fbo::draw_arrays(const buffer& buffer, GLenum mode, GLsizei count, GLint first) const
|
||||
{
|
||||
buffer.bind(buffer::target::array);
|
||||
draw_arrays(mode, count, first);
|
||||
}
|
||||
|
||||
void fbo::draw_arrays(const vao& buffer, GLenum mode, GLsizei count, GLint first) const
|
||||
{
|
||||
buffer.bind();
|
||||
draw_arrays(mode, count, first);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(GLenum mode, GLsizei count, indices_type type, const GLvoid* indices) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
glDrawElements(mode, count, static_cast<GLenum>(type), indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, GLenum mode, GLsizei count, indices_type type, const GLvoid* indices) const
|
||||
{
|
||||
buffer.bind(buffer::target::array);
|
||||
glDrawElements(mode, count, static_cast<GLenum>(type), indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(GLenum mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset) const
|
||||
{
|
||||
indices.bind(buffer::target::element_array);
|
||||
glDrawElements(mode, count, static_cast<GLenum>(type), reinterpret_cast<GLvoid*>(indices_buffer_offset));
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer_, GLenum mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset) const
|
||||
{
|
||||
buffer_.bind(buffer::target::array);
|
||||
draw_elements(mode, count, type, indices, indices_buffer_offset);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(GLenum mode, GLsizei count, const GLubyte* indices) const
|
||||
{
|
||||
draw_elements(mode, count, indices_type::ubyte, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLubyte* indices) const
|
||||
{
|
||||
draw_elements(buffer, mode, count, indices_type::ubyte, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(GLenum mode, GLsizei count, const GLushort* indices) const
|
||||
{
|
||||
draw_elements(mode, count, indices_type::ushort, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLushort* indices) const
|
||||
{
|
||||
draw_elements(buffer, mode, count, indices_type::ushort, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(GLenum mode, GLsizei count, const GLuint* indices) const
|
||||
{
|
||||
draw_elements(mode, count, indices_type::uint, indices);
|
||||
}
|
||||
|
||||
void fbo::draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLuint* indices) const
|
||||
{
|
||||
draw_elements(buffer, mode, count, indices_type::uint, indices);
|
||||
}
|
||||
|
||||
void fbo::clear(buffers buffers_) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
glClear(static_cast<GLbitfield>(buffers_));
|
||||
}
|
||||
|
||||
void fbo::clear(buffers buffers_, color4f color_value, double depth_value, u8 stencil_value) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
glClearColor(color_value.r, color_value.g, color_value.b, color_value.a);
|
||||
glClearDepth(depth_value);
|
||||
glClearStencil(stencil_value);
|
||||
clear(buffers_);
|
||||
}
|
||||
|
||||
void fbo::copy_from(const void* pixels, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
pixel_settings.apply();
|
||||
glDrawPixels(size.width, size.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), pixels);
|
||||
}
|
||||
|
||||
void fbo::copy_from(const buffer& buf, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
buffer::save_binding_state save_buffer(buffer::target::pixel_unpack, buf);
|
||||
pixel_settings.apply();
|
||||
glDrawPixels(size.width, size.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), nullptr);
|
||||
}
|
||||
|
||||
void fbo::copy_to(void* pixels, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
pixel_settings.apply();
|
||||
glReadPixels(coord.x, coord.y, coord.width, coord.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), pixels);
|
||||
}
|
||||
|
||||
void fbo::copy_to(const buffer& buf, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings) const
|
||||
{
|
||||
save_binding_state save(*this);
|
||||
buffer::save_binding_state save_buffer(buffer::target::pixel_pack, buf);
|
||||
pixel_settings.apply();
|
||||
glReadPixels(coord.x, coord.y, coord.width, coord.height, static_cast<GLenum>(format_), static_cast<GLenum>(type_), nullptr);
|
||||
}
|
||||
|
||||
fbo fbo::get_bound_draw_buffer()
|
||||
{
|
||||
GLint value;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &value);
|
||||
|
||||
return{ static_cast<GLuint>(value) };
|
||||
}
|
||||
|
||||
fbo fbo::get_bound_read_buffer()
|
||||
{
|
||||
GLint value;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &value);
|
||||
|
||||
return{ static_cast<GLuint>(value) };
|
||||
}
|
||||
|
||||
fbo fbo::get_bound_buffer()
|
||||
{
|
||||
GLint value;
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value);
|
||||
|
||||
return{ static_cast<GLuint>(value) };
|
||||
}
|
||||
|
||||
GLuint fbo::id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void fbo::set_id(GLuint id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
void fbo::set_extents(const size2i& extents)
|
||||
{
|
||||
m_size = extents;
|
||||
}
|
||||
|
||||
size2i fbo::get_extents() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool fbo::matches(const std::array<GLuint, 4>& color_targets, GLuint depth_stencil_target) const
|
||||
{
|
||||
for (u32 index = 0; index < 4; ++index)
|
||||
{
|
||||
if (color[index].resource_id() != color_targets[index])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const auto depth_resource = depth.resource_id() | depth_stencil.resource_id();
|
||||
return (depth_resource == depth_stencil_target);
|
||||
}
|
||||
|
||||
bool fbo::references_any(const std::vector<GLuint>& resources) const
|
||||
{
|
||||
return std::any_of(m_resource_bindings.cbegin(), m_resource_bindings.cend(), [&resources](const auto& e)
|
||||
{
|
||||
return std::find(resources.cbegin(), resources.cend(), e.second) != resources.cend();
|
||||
});
|
||||
}
|
||||
}
|
242
rpcs3/Emu/RSX/GL/glutils/fbo.h
Normal file
242
rpcs3/Emu/RSX/GL/glutils/fbo.h
Normal file
@ -0,0 +1,242 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "image.h"
|
||||
#include "pixel_settings.hpp"
|
||||
|
||||
#include "Utilities/geometry.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
enum class buffers
|
||||
{
|
||||
none = 0,
|
||||
color = GL_COLOR_BUFFER_BIT,
|
||||
depth = GL_DEPTH_BUFFER_BIT,
|
||||
stencil = GL_STENCIL_BUFFER_BIT,
|
||||
|
||||
color_depth = color | depth,
|
||||
color_depth_stencil = color | depth | stencil,
|
||||
color_stencil = color | stencil,
|
||||
|
||||
depth_stencil = depth | stencil
|
||||
};
|
||||
|
||||
enum class indices_type
|
||||
{
|
||||
ubyte = GL_UNSIGNED_BYTE,
|
||||
ushort = GL_UNSIGNED_SHORT,
|
||||
uint = GL_UNSIGNED_INT
|
||||
};
|
||||
|
||||
class vao;
|
||||
|
||||
class fbo
|
||||
{
|
||||
GLuint m_id = GL_NONE;
|
||||
size2i m_size;
|
||||
|
||||
protected:
|
||||
std::unordered_map<GLenum, GLuint> m_resource_bindings;
|
||||
|
||||
public:
|
||||
fbo() = default;
|
||||
|
||||
fbo(GLuint id)
|
||||
{
|
||||
set_id(id);
|
||||
}
|
||||
|
||||
~fbo()
|
||||
{
|
||||
if (created())
|
||||
remove();
|
||||
}
|
||||
|
||||
class save_binding_state
|
||||
{
|
||||
GLint m_last_binding;
|
||||
bool reset = true;
|
||||
|
||||
public:
|
||||
save_binding_state(const fbo& new_binding)
|
||||
{
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_last_binding);
|
||||
|
||||
if (m_last_binding + 0u != new_binding.id())
|
||||
new_binding.bind();
|
||||
else
|
||||
reset = false;
|
||||
}
|
||||
|
||||
~save_binding_state()
|
||||
{
|
||||
if (reset)
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_last_binding);
|
||||
}
|
||||
};
|
||||
|
||||
class attachment
|
||||
{
|
||||
public:
|
||||
enum class type
|
||||
{
|
||||
color = GL_COLOR_ATTACHMENT0,
|
||||
depth = GL_DEPTH_ATTACHMENT,
|
||||
stencil = GL_STENCIL_ATTACHMENT,
|
||||
depth_stencil = GL_DEPTH_STENCIL_ATTACHMENT
|
||||
};
|
||||
|
||||
protected:
|
||||
GLuint m_id = GL_NONE;
|
||||
fbo& m_parent;
|
||||
|
||||
attachment(fbo& parent)
|
||||
: m_parent(parent)
|
||||
{}
|
||||
|
||||
public:
|
||||
attachment(fbo& parent, type type)
|
||||
: m_id(static_cast<int>(type))
|
||||
, m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void set_id(uint id)
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
uint id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
GLuint resource_id() const
|
||||
{
|
||||
const auto found = m_parent.m_resource_bindings.find(m_id);
|
||||
if (found != m_parent.m_resource_bindings.end())
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void operator = (const texture& rhs)
|
||||
{
|
||||
ensure(rhs.get_target() == texture::target::texture2D);
|
||||
m_parent.m_resource_bindings[m_id] = rhs.id();
|
||||
DSA_CALL2(NamedFramebufferTexture, m_parent.id(), m_id, rhs.id(), 0);
|
||||
}
|
||||
|
||||
void operator = (const GLuint rhs)
|
||||
{
|
||||
m_parent.m_resource_bindings[m_id] = rhs;
|
||||
DSA_CALL2(NamedFramebufferTexture, m_parent.id(), m_id, rhs, 0);
|
||||
}
|
||||
};
|
||||
|
||||
class indexed_attachment : public attachment
|
||||
{
|
||||
public:
|
||||
indexed_attachment(fbo& parent, type type) : attachment(parent, type)
|
||||
{
|
||||
}
|
||||
|
||||
attachment operator[](int index) const
|
||||
{
|
||||
return{ m_parent, type(id() + index) };
|
||||
}
|
||||
|
||||
std::vector<attachment> range(int from, int count) const
|
||||
{
|
||||
std::vector<attachment> result;
|
||||
|
||||
for (int i = from; i < from + count; ++i)
|
||||
result.push_back((*this)[i]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
using attachment::operator =;
|
||||
};
|
||||
|
||||
struct null_attachment : public attachment
|
||||
{
|
||||
null_attachment(fbo& parent)
|
||||
: attachment(parent)
|
||||
{}
|
||||
};
|
||||
|
||||
indexed_attachment color{ *this, attachment::type::color };
|
||||
attachment depth{ *this, attachment::type::depth };
|
||||
attachment stencil{ *this, attachment::type::stencil };
|
||||
attachment depth_stencil{ *this, attachment::type::depth_stencil };
|
||||
null_attachment no_color{ *this };
|
||||
|
||||
enum class target
|
||||
{
|
||||
read_frame_buffer = GL_READ_FRAMEBUFFER,
|
||||
draw_frame_buffer = GL_DRAW_FRAMEBUFFER
|
||||
};
|
||||
|
||||
void create();
|
||||
void bind() const;
|
||||
void blit(const fbo& dst, areai src_area, areai dst_area, buffers buffers_ = buffers::color, filter filter_ = filter::nearest) const;
|
||||
void bind_as(target target_) const;
|
||||
void remove();
|
||||
bool created() const;
|
||||
bool check() const;
|
||||
|
||||
void recreate();
|
||||
void draw_buffer(const attachment& buffer) const;
|
||||
void draw_buffers(const std::initializer_list<attachment>& indexes) const;
|
||||
|
||||
void read_buffer(const attachment& buffer) const;
|
||||
|
||||
void draw_arrays(GLenum mode, GLsizei count, GLint first = 0) const;
|
||||
void draw_arrays(const buffer& buffer, GLenum mode, GLsizei count, GLint first = 0) const;
|
||||
void draw_arrays(const vao& buffer, GLenum mode, GLsizei count, GLint first = 0) const;
|
||||
|
||||
void draw_elements(GLenum mode, GLsizei count, indices_type type, const GLvoid* indices) const;
|
||||
void draw_elements(const buffer& buffer, GLenum mode, GLsizei count, indices_type type, const GLvoid* indices) const;
|
||||
void draw_elements(GLenum mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset = 0) const;
|
||||
void draw_elements(const buffer& buffer_, GLenum mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset = 0) const;
|
||||
void draw_elements(GLenum mode, GLsizei count, const GLubyte* indices) const;
|
||||
void draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLubyte* indices) const;
|
||||
void draw_elements(GLenum mode, GLsizei count, const GLushort* indices) const;
|
||||
void draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLushort* indices) const;
|
||||
void draw_elements(GLenum mode, GLsizei count, const GLuint* indices) const;
|
||||
void draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLuint* indices) const;
|
||||
|
||||
void clear(buffers buffers_) const;
|
||||
void clear(buffers buffers_, color4f color_value, double depth_value, u8 stencil_value) const;
|
||||
|
||||
void copy_from(const void* pixels, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings = pixel_unpack_settings()) const;
|
||||
void copy_from(const buffer& buf, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings = pixel_unpack_settings()) const;
|
||||
|
||||
void copy_to(void* pixels, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings = pixel_pack_settings()) const;
|
||||
void copy_to(const buffer& buf, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings = pixel_pack_settings()) const;
|
||||
|
||||
static fbo get_bound_draw_buffer();
|
||||
static fbo get_bound_read_buffer();
|
||||
static fbo get_bound_buffer();
|
||||
|
||||
GLuint id() const;
|
||||
void set_id(GLuint id);
|
||||
|
||||
void set_extents(const size2i& extents);
|
||||
size2i get_extents() const;
|
||||
|
||||
bool matches(const std::array<GLuint, 4>& color_targets, GLuint depth_stencil_target) const;
|
||||
bool references_any(const std::vector<GLuint>& resources) const;
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return created();
|
||||
}
|
||||
};
|
||||
|
||||
extern const fbo screen;
|
||||
}
|
@ -224,7 +224,7 @@ namespace gl
|
||||
}
|
||||
}
|
||||
|
||||
void texture_view::create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle)
|
||||
void texture_view::create(texture* data, GLenum target, GLuint min_level, GLuint num_levels, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle)
|
||||
{
|
||||
m_target = target;
|
||||
m_format = sizedfmt_to_ifmt(sized_format);
|
||||
@ -243,7 +243,7 @@ namespace gl
|
||||
}
|
||||
|
||||
glGenTextures(1, &m_id);
|
||||
glTextureView(m_id, target, data->id(), m_format, 0, data->levels(), 0, num_layers);
|
||||
glTextureView(m_id, target, data->id(), m_format, min_level, num_levels, 0, num_layers);
|
||||
|
||||
if (argb_swizzle)
|
||||
{
|
||||
|
@ -25,6 +25,22 @@ namespace gl
|
||||
stencil = 4
|
||||
};
|
||||
|
||||
enum class filter
|
||||
{
|
||||
nearest = GL_NEAREST,
|
||||
linear = GL_LINEAR
|
||||
};
|
||||
|
||||
enum class min_filter
|
||||
{
|
||||
nearest = GL_NEAREST,
|
||||
linear = GL_LINEAR,
|
||||
nearest_mipmap_nearest = GL_NEAREST_MIPMAP_NEAREST,
|
||||
nearest_mipmap_linear = GL_NEAREST_MIPMAP_LINEAR,
|
||||
linear_mipmap_nearest = GL_LINEAR_MIPMAP_NEAREST,
|
||||
linear_mipmap_linear = GL_LINEAR_MIPMAP_LINEAR
|
||||
};
|
||||
|
||||
class texture
|
||||
{
|
||||
friend class texture_view;
|
||||
@ -301,7 +317,7 @@ namespace gl
|
||||
|
||||
GLenum component_swizzle[4];
|
||||
|
||||
void create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr);
|
||||
void create(texture* data, GLenum target, GLenum sized_format, GLuint min_level, GLuint num_levels, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr);
|
||||
|
||||
public:
|
||||
texture_view(const texture_view&) = delete;
|
||||
@ -311,7 +327,7 @@ namespace gl
|
||||
const GLenum* argb_swizzle = nullptr,
|
||||
GLenum aspect_flags = image_aspect::color | image_aspect::depth)
|
||||
{
|
||||
create(data, target, sized_format, aspect_flags, argb_swizzle);
|
||||
create(data, target, sized_format, 0, data->levels(), aspect_flags, argb_swizzle);
|
||||
}
|
||||
|
||||
texture_view(texture* data, const GLenum* argb_swizzle = nullptr,
|
||||
@ -319,7 +335,16 @@ namespace gl
|
||||
{
|
||||
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);
|
||||
create(data, target, sized_format, 0, data->levels(), aspect_flags, argb_swizzle);
|
||||
}
|
||||
|
||||
texture_view(texture* data, GLuint mip_level,
|
||||
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, mip_level, 1, aspect_flags, argb_swizzle);
|
||||
}
|
||||
|
||||
virtual ~texture_view();
|
||||
|
217
rpcs3/Emu/RSX/GL/glutils/program.cpp
Normal file
217
rpcs3/Emu/RSX/GL/glutils/program.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
#include "stdafx.h"
|
||||
#include "program.h"
|
||||
#include "state_tracker.hpp"
|
||||
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
namespace glsl
|
||||
{
|
||||
void shader::precompile()
|
||||
{
|
||||
const char* str = source.c_str();
|
||||
const GLint length = ::narrow<GLint>(source.length());
|
||||
|
||||
if (g_cfg.video.log_programs)
|
||||
{
|
||||
std::string base_name;
|
||||
switch (type)
|
||||
{
|
||||
case ::glsl::program_domain::glsl_vertex_program:
|
||||
base_name = "shaderlog/VertexProgram";
|
||||
break;
|
||||
case ::glsl::program_domain::glsl_fragment_program:
|
||||
base_name = "shaderlog/FragmentProgram";
|
||||
break;
|
||||
case ::glsl::program_domain::glsl_compute_program:
|
||||
base_name = "shaderlog/ComputeProgram";
|
||||
break;
|
||||
}
|
||||
|
||||
fs::file(fs::get_cache_dir() + base_name + std::to_string(m_id) + ".glsl", fs::rewrite).write(str, length);
|
||||
}
|
||||
|
||||
glShaderSource(m_id, 1, &str, &length);
|
||||
|
||||
m_init_fence.create();
|
||||
flush_command_queue(m_init_fence);
|
||||
}
|
||||
|
||||
void shader::create(::glsl::program_domain type_, const std::string & src)
|
||||
{
|
||||
type = type_;
|
||||
source = src;
|
||||
|
||||
GLenum shader_type{};
|
||||
switch (type)
|
||||
{
|
||||
case ::glsl::program_domain::glsl_vertex_program:
|
||||
shader_type = GL_VERTEX_SHADER;
|
||||
break;
|
||||
case ::glsl::program_domain::glsl_fragment_program:
|
||||
shader_type = GL_FRAGMENT_SHADER;
|
||||
break;
|
||||
case ::glsl::program_domain::glsl_compute_program:
|
||||
shader_type = GL_COMPUTE_SHADER;
|
||||
break;
|
||||
default:
|
||||
rsx_log.fatal("gl::glsl::shader::compile(): Unhandled shader type (%d)", +type_);
|
||||
return;
|
||||
}
|
||||
|
||||
m_id = glCreateShader(shader_type);
|
||||
precompile();
|
||||
}
|
||||
|
||||
shader& shader::compile()
|
||||
{
|
||||
std::lock_guard lock(m_compile_lock);
|
||||
if (m_is_compiled)
|
||||
{
|
||||
// Another thread compiled this already
|
||||
return *this;
|
||||
}
|
||||
|
||||
ensure(!m_init_fence.is_empty()); // Do not attempt to compile a shader_view!!
|
||||
m_init_fence.server_wait_sync();
|
||||
|
||||
glCompileShader(m_id);
|
||||
|
||||
GLint status = GL_FALSE;
|
||||
glGetShaderiv(m_id, GL_COMPILE_STATUS, &status);
|
||||
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
GLint length = 0;
|
||||
glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &length);
|
||||
|
||||
std::string error_msg;
|
||||
if (length)
|
||||
{
|
||||
std::unique_ptr<GLchar[]> buf(new char[length + 1]);
|
||||
glGetShaderInfoLog(m_id, length, nullptr, buf.get());
|
||||
error_msg = buf.get();
|
||||
}
|
||||
|
||||
rsx_log.fatal("Compilation failed: %s\nsource: %s", error_msg, source);
|
||||
}
|
||||
|
||||
m_compiled_fence.create();
|
||||
flush_command_queue(m_compiled_fence);
|
||||
|
||||
m_is_compiled = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool program::uniforms_t::has_location(const std::string & name, int* location)
|
||||
{
|
||||
auto found = locations.find(name);
|
||||
if (found != locations.end())
|
||||
{
|
||||
if (location)
|
||||
{
|
||||
*location = found->second;
|
||||
}
|
||||
|
||||
return (found->second >= 0);
|
||||
}
|
||||
|
||||
auto result = glGetUniformLocation(m_program.id(), name.c_str());
|
||||
locations[name] = result;
|
||||
|
||||
if (location)
|
||||
{
|
||||
*location = result;
|
||||
}
|
||||
|
||||
return (result >= 0);
|
||||
}
|
||||
|
||||
GLint program::uniforms_t::location(const std::string& name)
|
||||
{
|
||||
auto found = locations.find(name);
|
||||
if (found != locations.end())
|
||||
{
|
||||
if (found->second >= 0)
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsx_log.fatal("%s not found.", name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto result = glGetUniformLocation(m_program.id(), name.c_str());
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
rsx_log.fatal("%s not found.", name);
|
||||
return result;
|
||||
}
|
||||
|
||||
locations[name] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
void program::link(std::function<void(program*)> init_func)
|
||||
{
|
||||
glLinkProgram(m_id);
|
||||
|
||||
GLint status = GL_FALSE;
|
||||
glGetProgramiv(m_id, GL_LINK_STATUS, &status);
|
||||
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
GLint length = 0;
|
||||
glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &length);
|
||||
|
||||
std::string error_msg;
|
||||
if (length)
|
||||
{
|
||||
std::unique_ptr<GLchar[]> buf(new char[length + 1]);
|
||||
glGetProgramInfoLog(m_id, length, nullptr, buf.get());
|
||||
error_msg = buf.get();
|
||||
}
|
||||
|
||||
rsx_log.fatal("Linkage failed: %s", error_msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (init_func)
|
||||
{
|
||||
init_func(this);
|
||||
}
|
||||
|
||||
m_fence.create();
|
||||
flush_command_queue(m_fence);
|
||||
}
|
||||
}
|
||||
|
||||
void program::validate()
|
||||
{
|
||||
glValidateProgram(m_id);
|
||||
|
||||
GLint status = GL_FALSE;
|
||||
glGetProgramiv(m_id, GL_VALIDATE_STATUS, &status);
|
||||
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
GLint length = 0;
|
||||
glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &length);
|
||||
|
||||
std::string error_msg;
|
||||
if (length)
|
||||
{
|
||||
std::unique_ptr<GLchar[]> buf(new char[length + 1]);
|
||||
glGetProgramInfoLog(m_id, length, nullptr, buf.get());
|
||||
error_msg = buf.get();
|
||||
}
|
||||
|
||||
rsx_log.error("Validation failed: %s", error_msg.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
197
rpcs3/Emu/RSX/GL/glutils/program.h
Normal file
197
rpcs3/Emu/RSX/GL/glutils/program.h
Normal file
@ -0,0 +1,197 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "sync.hpp"
|
||||
|
||||
#include "Emu/RSX/Program/GLSLTypes.h"
|
||||
#include "Utilities/geometry.h"
|
||||
#include "Utilities/mutex.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
namespace glsl
|
||||
{
|
||||
class shader
|
||||
{
|
||||
std::string source;
|
||||
::glsl::program_domain type;
|
||||
GLuint m_id = GL_NONE;
|
||||
|
||||
fence m_compiled_fence;
|
||||
fence m_init_fence;
|
||||
|
||||
shared_mutex m_compile_lock;
|
||||
atomic_t<bool> m_is_compiled{};
|
||||
|
||||
void precompile();
|
||||
|
||||
public:
|
||||
shader() = default;
|
||||
|
||||
shader(::glsl::program_domain type_, const std::string& src)
|
||||
{
|
||||
create(type_, src);
|
||||
}
|
||||
|
||||
~shader()
|
||||
{
|
||||
if (created())
|
||||
{
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
void remove()
|
||||
{
|
||||
glDeleteShader(m_id);
|
||||
m_id = GL_NONE;
|
||||
}
|
||||
|
||||
void create(::glsl::program_domain type_, const std::string& src);
|
||||
|
||||
shader& compile();
|
||||
|
||||
uint id() const { return m_id; }
|
||||
|
||||
const std::string& get_source() const { return source; }
|
||||
|
||||
fence get_compile_fence_sync() const { return m_compiled_fence; }
|
||||
|
||||
bool created() const { return m_id != GL_NONE; }
|
||||
|
||||
bool compiled() const { return m_is_compiled; }
|
||||
|
||||
explicit operator bool() const { return created(); }
|
||||
};
|
||||
|
||||
class program
|
||||
{
|
||||
GLuint m_id = GL_NONE;
|
||||
fence m_fence;
|
||||
|
||||
public:
|
||||
class uniform_t
|
||||
{
|
||||
program& m_program;
|
||||
GLint m_location;
|
||||
|
||||
public:
|
||||
uniform_t(program& program, GLint location)
|
||||
: m_program(program)
|
||||
, m_location(location)
|
||||
{
|
||||
}
|
||||
|
||||
GLint location() const
|
||||
{
|
||||
return m_location;
|
||||
}
|
||||
|
||||
void operator = (int rhs) const { glProgramUniform1i(m_program.id(), location(), rhs); }
|
||||
void operator = (unsigned rhs) const { glProgramUniform1ui(m_program.id(), location(), rhs); }
|
||||
void operator = (float rhs) const { glProgramUniform1f(m_program.id(), location(), rhs); }
|
||||
void operator = (bool rhs) const { glProgramUniform1ui(m_program.id(), location(), rhs ? 1 : 0); }
|
||||
void operator = (const color1i& rhs) const { glProgramUniform1i(m_program.id(), location(), rhs.r); }
|
||||
void operator = (const color1f& rhs) const { glProgramUniform1f(m_program.id(), location(), rhs.r); }
|
||||
void operator = (const color2i& rhs) const { glProgramUniform2i(m_program.id(), location(), rhs.r, rhs.g); }
|
||||
void operator = (const color2f& rhs) const { glProgramUniform2f(m_program.id(), location(), rhs.r, rhs.g); }
|
||||
void operator = (const color3i& rhs) const { glProgramUniform3i(m_program.id(), location(), rhs.r, rhs.g, rhs.b); }
|
||||
void operator = (const color3f& rhs) const { glProgramUniform3f(m_program.id(), location(), rhs.r, rhs.g, rhs.b); }
|
||||
void operator = (const color4i& rhs) const { glProgramUniform4i(m_program.id(), location(), rhs.r, rhs.g, rhs.b, rhs.a); }
|
||||
void operator = (const color4f& rhs) const { glProgramUniform4f(m_program.id(), location(), rhs.r, rhs.g, rhs.b, rhs.a); }
|
||||
void operator = (const areaf& rhs) const { glProgramUniform4f(m_program.id(), location(), rhs.x1, rhs.y1, rhs.x2, rhs.y2); }
|
||||
void operator = (const areai& rhs) const { glProgramUniform4i(m_program.id(), location(), rhs.x1, rhs.y1, rhs.x2, rhs.y2); }
|
||||
void operator = (const std::vector<int>& rhs) const { glProgramUniform1iv(m_program.id(), location(), ::size32(rhs), rhs.data()); }
|
||||
};
|
||||
|
||||
class uniforms_t
|
||||
{
|
||||
program& m_program;
|
||||
std::unordered_map<std::string, GLint> locations;
|
||||
|
||||
public:
|
||||
uniforms_t(program* program)
|
||||
: m_program(*program)
|
||||
{}
|
||||
|
||||
void clear() { locations.clear(); }
|
||||
|
||||
bool has_location(const std::string& name, int* location = nullptr);
|
||||
|
||||
GLint location(const std::string& name);
|
||||
|
||||
uniform_t operator[](GLint location) { return{ m_program, location }; }
|
||||
|
||||
uniform_t operator[](const std::string& name) { return{ m_program, location(name) }; }
|
||||
|
||||
} uniforms{ this };
|
||||
|
||||
public:
|
||||
program() = default;
|
||||
program(const program&) = delete;
|
||||
|
||||
~program()
|
||||
{
|
||||
if (created())
|
||||
{
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
program& recreate()
|
||||
{
|
||||
remove();
|
||||
return create();
|
||||
}
|
||||
|
||||
program& create()
|
||||
{
|
||||
m_id = glCreateProgram();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void remove()
|
||||
{
|
||||
glDeleteProgram(m_id);
|
||||
m_id = GL_NONE;
|
||||
uniforms.clear();
|
||||
}
|
||||
|
||||
void link(std::function<void(program*)> init_func = {});
|
||||
|
||||
void validate();
|
||||
|
||||
void sync()
|
||||
{
|
||||
if (!m_fence.check_signaled())
|
||||
{
|
||||
m_fence.server_wait_sync();
|
||||
}
|
||||
}
|
||||
|
||||
program& attach(const shader& shader_)
|
||||
{
|
||||
glAttachShader(m_id, shader_.id());
|
||||
return *this;
|
||||
}
|
||||
|
||||
program& bind_attribute_location(const std::string& name, int index)
|
||||
{
|
||||
glBindAttribLocation(m_id, index, name.c_str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
program& bind_fragment_data_location(const std::string& name, int color_number)
|
||||
{
|
||||
glBindFragDataLocation(m_id, color_number, name.c_str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
GLuint id() const { return m_id; }
|
||||
|
||||
bool created() const { return m_id != GL_NONE; }
|
||||
|
||||
explicit operator bool() const { return created(); }
|
||||
};
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "buffer_object.h"
|
||||
#include "sync.hpp"
|
||||
#include "Utilities/address_range.h"
|
||||
|
||||
namespace gl
|
||||
|
@ -348,4 +348,7 @@ namespace gl
|
||||
|
||||
void set_primary_context_thread(bool = true);
|
||||
bool is_primary_context_thread();
|
||||
|
||||
class fence;
|
||||
void flush_command_queue(fence& fence_obj);
|
||||
}
|
||||
|
129
rpcs3/Emu/RSX/GL/glutils/sync.hpp
Normal file
129
rpcs3/Emu/RSX/GL/glutils/sync.hpp
Normal file
@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
class fence
|
||||
{
|
||||
GLsync m_value = nullptr;
|
||||
mutable GLenum flags = GL_SYNC_FLUSH_COMMANDS_BIT;
|
||||
mutable bool signaled = false;
|
||||
|
||||
public:
|
||||
|
||||
fence() = default;
|
||||
~fence() = default;
|
||||
|
||||
void create()
|
||||
{
|
||||
m_value = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
flags = GL_SYNC_FLUSH_COMMANDS_BIT;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
glDeleteSync(m_value);
|
||||
m_value = nullptr;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (m_value != nullptr)
|
||||
destroy();
|
||||
|
||||
create();
|
||||
}
|
||||
|
||||
bool is_empty() const
|
||||
{
|
||||
return (m_value == nullptr);
|
||||
}
|
||||
|
||||
bool check_signaled() const
|
||||
{
|
||||
ensure(m_value);
|
||||
|
||||
if (signaled)
|
||||
return true;
|
||||
|
||||
if (flags)
|
||||
{
|
||||
GLenum err = glClientWaitSync(m_value, flags, 0);
|
||||
flags = 0;
|
||||
|
||||
if (!(err == GL_ALREADY_SIGNALED || err == GL_CONDITION_SATISFIED))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
GLint status = GL_UNSIGNALED;
|
||||
GLint tmp;
|
||||
|
||||
glGetSynciv(m_value, GL_SYNC_STATUS, 4, &tmp, &status);
|
||||
|
||||
if (status != GL_SIGNALED)
|
||||
return false;
|
||||
}
|
||||
|
||||
signaled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wait_for_signal()
|
||||
{
|
||||
ensure(m_value);
|
||||
|
||||
if (signaled == GL_FALSE)
|
||||
{
|
||||
GLenum err = GL_WAIT_FAILED;
|
||||
bool done = false;
|
||||
|
||||
while (!done)
|
||||
{
|
||||
if (flags)
|
||||
{
|
||||
err = glClientWaitSync(m_value, flags, 0);
|
||||
flags = 0;
|
||||
|
||||
switch (err)
|
||||
{
|
||||
default:
|
||||
rsx_log.error("gl::fence sync returned unknown error 0x%X", err);
|
||||
[[fallthrough]];
|
||||
case GL_ALREADY_SIGNALED:
|
||||
case GL_CONDITION_SATISFIED:
|
||||
done = true;
|
||||
break;
|
||||
case GL_TIMEOUT_EXPIRED:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GLint status = GL_UNSIGNALED;
|
||||
GLint tmp;
|
||||
|
||||
glGetSynciv(m_value, GL_SYNC_STATUS, 4, &tmp, &status);
|
||||
|
||||
if (status == GL_SIGNALED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
signaled = (err == GL_ALREADY_SIGNALED || err == GL_CONDITION_SATISFIED);
|
||||
}
|
||||
|
||||
glDeleteSync(m_value);
|
||||
m_value = nullptr;
|
||||
|
||||
return signaled;
|
||||
}
|
||||
|
||||
void server_wait_sync() const
|
||||
{
|
||||
ensure(m_value != nullptr);
|
||||
glWaitSync(m_value, 0, GL_TIMEOUT_IGNORED);
|
||||
}
|
||||
};
|
||||
}
|
306
rpcs3/Emu/RSX/GL/glutils/vao.hpp
Normal file
306
rpcs3/Emu/RSX/GL/glutils/vao.hpp
Normal file
@ -0,0 +1,306 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "buffer_object.h"
|
||||
|
||||
#include "Utilities/geometry.h"
|
||||
|
||||
namespace gl
|
||||
{
|
||||
class vao;
|
||||
|
||||
class buffer_pointer
|
||||
{
|
||||
public:
|
||||
enum class type
|
||||
{
|
||||
s8 = GL_BYTE,
|
||||
u8 = GL_UNSIGNED_BYTE,
|
||||
s16 = GL_SHORT,
|
||||
u16 = GL_UNSIGNED_SHORT,
|
||||
s32 = GL_INT,
|
||||
u32 = GL_UNSIGNED_INT,
|
||||
f16 = GL_HALF_FLOAT,
|
||||
f32 = GL_FLOAT,
|
||||
f64 = GL_DOUBLE,
|
||||
fixed = GL_FIXED,
|
||||
s32_2_10_10_10_rev = GL_INT_2_10_10_10_REV,
|
||||
u32_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
u32_10f_11f_11f_rev = GL_UNSIGNED_INT_10F_11F_11F_REV
|
||||
};
|
||||
|
||||
private:
|
||||
vao* m_vao;
|
||||
u32 m_offset;
|
||||
u32 m_stride;
|
||||
u32 m_size = 4;
|
||||
type m_type = type::f32;
|
||||
bool m_normalize = false;
|
||||
|
||||
public:
|
||||
buffer_pointer(vao* vao, u32 offset = 0, u32 stride = 0)
|
||||
: m_vao(vao)
|
||||
, m_offset(offset)
|
||||
, m_stride(stride)
|
||||
{
|
||||
}
|
||||
|
||||
const class ::gl::vao& get_vao() const
|
||||
{
|
||||
return *m_vao;
|
||||
}
|
||||
|
||||
class ::gl::vao& get_vao()
|
||||
{
|
||||
return *m_vao;
|
||||
}
|
||||
|
||||
buffer_pointer& offset(u32 value)
|
||||
{
|
||||
m_offset = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
u32 offset() const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
buffer_pointer& stride(u32 value)
|
||||
{
|
||||
m_stride = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
u32 stride() const
|
||||
{
|
||||
return m_stride;
|
||||
}
|
||||
|
||||
buffer_pointer& size(u32 value)
|
||||
{
|
||||
m_size = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
u32 size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
buffer_pointer& set_type(type value)
|
||||
{
|
||||
m_type = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
type get_type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
buffer_pointer& normalize(bool value)
|
||||
{
|
||||
m_normalize = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool normalize() const
|
||||
{
|
||||
return m_normalize;
|
||||
}
|
||||
|
||||
buffer_pointer& operator >> (u32 value)
|
||||
{
|
||||
return stride(value);
|
||||
}
|
||||
|
||||
buffer_pointer& config(type type_ = type::f32, u32 size_ = 4, bool normalize_ = false)
|
||||
{
|
||||
return set_type(type_).size(size_).normalize(normalize_);
|
||||
}
|
||||
};
|
||||
|
||||
class attrib_t;
|
||||
|
||||
class vao
|
||||
{
|
||||
template<buffer::target BindId, uint GetStateId>
|
||||
class entry
|
||||
{
|
||||
vao& m_parent;
|
||||
|
||||
public:
|
||||
using save_binding_state = save_binding_state_base<entry, (static_cast<GLuint>(BindId)), GetStateId>;
|
||||
|
||||
entry(vao* parent) noexcept : m_parent(*parent)
|
||||
{
|
||||
}
|
||||
|
||||
entry& operator = (const buffer& buf) noexcept
|
||||
{
|
||||
m_parent.bind();
|
||||
buf.bind(BindId);
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
GLuint m_id = GL_NONE;
|
||||
|
||||
public:
|
||||
entry<buffer::target::pixel_pack, GL_PIXEL_PACK_BUFFER_BINDING> pixel_pack_buffer{ this };
|
||||
entry<buffer::target::pixel_unpack, GL_PIXEL_UNPACK_BUFFER_BINDING> pixel_unpack_buffer{ this };
|
||||
entry<buffer::target::array, GL_ARRAY_BUFFER_BINDING> array_buffer{ this };
|
||||
entry<buffer::target::element_array, GL_ELEMENT_ARRAY_BUFFER_BINDING> element_array_buffer{ this };
|
||||
|
||||
vao() = default;
|
||||
vao(const vao&) = delete;
|
||||
|
||||
vao(vao&& vao_) noexcept
|
||||
{
|
||||
swap(vao_);
|
||||
}
|
||||
vao(GLuint id) noexcept
|
||||
{
|
||||
set_id(id);
|
||||
}
|
||||
|
||||
~vao() noexcept
|
||||
{
|
||||
if (created())
|
||||
remove();
|
||||
}
|
||||
|
||||
void swap(vao& vao_) noexcept
|
||||
{
|
||||
auto my_old_id = id();
|
||||
set_id(vao_.id());
|
||||
vao_.set_id(my_old_id);
|
||||
}
|
||||
|
||||
vao& operator = (const vao& rhs) = delete;
|
||||
vao& operator = (vao&& rhs) noexcept
|
||||
{
|
||||
swap(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void bind() const noexcept
|
||||
{
|
||||
glBindVertexArray(m_id);
|
||||
}
|
||||
|
||||
void create() noexcept
|
||||
{
|
||||
glGenVertexArrays(1, &m_id);
|
||||
}
|
||||
|
||||
void remove() noexcept
|
||||
{
|
||||
if (m_id != GL_NONE)
|
||||
{
|
||||
glDeleteVertexArrays(1, &m_id);
|
||||
m_id = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
uint id() const noexcept
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void set_id(uint id) noexcept
|
||||
{
|
||||
m_id = id;
|
||||
}
|
||||
|
||||
bool created() const noexcept
|
||||
{
|
||||
return m_id != GL_NONE;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return created();
|
||||
}
|
||||
|
||||
void enable_for_attributes(std::initializer_list<GLuint> indexes) noexcept
|
||||
{
|
||||
for (auto& index : indexes)
|
||||
{
|
||||
glEnableVertexAttribArray(index);
|
||||
}
|
||||
}
|
||||
|
||||
void disable_for_attributes(std::initializer_list<GLuint> indexes) noexcept
|
||||
{
|
||||
for (auto& index : indexes)
|
||||
{
|
||||
glDisableVertexAttribArray(index);
|
||||
}
|
||||
}
|
||||
|
||||
void enable_for_attribute(GLuint index) noexcept
|
||||
{
|
||||
enable_for_attributes({ index });
|
||||
}
|
||||
|
||||
void disable_for_attribute(GLuint index) noexcept
|
||||
{
|
||||
disable_for_attributes({ index });
|
||||
}
|
||||
|
||||
buffer_pointer operator + (u32 offset) noexcept
|
||||
{
|
||||
return{ this, offset };
|
||||
}
|
||||
|
||||
buffer_pointer operator >> (u32 stride) noexcept
|
||||
{
|
||||
return{ this, {}, stride };
|
||||
}
|
||||
|
||||
operator buffer_pointer() noexcept
|
||||
{
|
||||
return{ this };
|
||||
}
|
||||
|
||||
attrib_t operator [] (u32 index) const noexcept;
|
||||
};
|
||||
|
||||
class attrib_t
|
||||
{
|
||||
GLint m_location;
|
||||
|
||||
public:
|
||||
attrib_t(GLint location)
|
||||
: m_location(location)
|
||||
{
|
||||
}
|
||||
|
||||
GLint location() const
|
||||
{
|
||||
return m_location;
|
||||
}
|
||||
|
||||
void operator = (float rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs); }
|
||||
void operator = (double rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs); }
|
||||
|
||||
void operator = (const color1f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs.r); }
|
||||
void operator = (const color1d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs.r); }
|
||||
void operator = (const color2f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2f(location(), rhs.r, rhs.g); }
|
||||
void operator = (const color2d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2d(location(), rhs.r, rhs.g); }
|
||||
void operator = (const color3f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3f(location(), rhs.r, rhs.g, rhs.b); }
|
||||
void operator = (const color3d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3d(location(), rhs.r, rhs.g, rhs.b); }
|
||||
void operator = (const color4f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); }
|
||||
void operator = (const color4d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4d(location(), rhs.r, rhs.g, rhs.b, rhs.a); }
|
||||
|
||||
void operator = (buffer_pointer& pointer) const
|
||||
{
|
||||
pointer.get_vao().enable_for_attribute(m_location);
|
||||
glVertexAttribPointer(location(), pointer.size(), static_cast<GLenum>(pointer.get_type()), pointer.normalize(),
|
||||
pointer.stride(), reinterpret_cast<const void*>(u64{ pointer.offset() }));
|
||||
}
|
||||
};
|
||||
}
|
@ -60,13 +60,18 @@
|
||||
<ClInclude Include="Emu\RSX\GL\GLGSRender.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLProcTable.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLProgramBuffer.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\blitter.h" />
|
||||
<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\fbo.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\pixel_settings.hpp" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\program.h" />
|
||||
<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\glutils\sync.hpp" />
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\vao.hpp" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLVertexProgram.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLHelpers.h" />
|
||||
<ClInclude Include="Emu\RSX\GL\GLRenderTargets.h" />
|
||||
@ -83,8 +88,11 @@
|
||||
<ClCompile Include="Emu\RSX\GL\GLGSRender.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\GLOverlays.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\GLPipelineCompiler.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\blitter.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\buffer_object.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\common.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\fbo.cpp" />
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\program.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" />
|
||||
|
@ -29,6 +29,15 @@
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\common.cpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\blitter.cpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\fbo.cpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\GL\glutils\program.cpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Emu\RSX\GL\GLTexture.h" />
|
||||
@ -68,6 +77,21 @@
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\pixel_settings.hpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\blitter.h">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\fbo.h">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\vao.hpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\program.h">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\GL\glutils\sync.hpp">
|
||||
<Filter>glutils</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="glutils">
|
||||
|
Loading…
Reference in New Issue
Block a user