rasterizer_cache: Remove usage of shared_ptr
This commit is contained in:
@ -143,7 +143,7 @@ protected:
|
||||
Memory::MemorySystem& memory;
|
||||
Pica::Regs& regs;
|
||||
|
||||
VertexArrayInfo vertex_info;
|
||||
VertexArrayInfo vertex_info{};
|
||||
std::vector<HardwareVertex> vertex_batch;
|
||||
bool shader_dirty = true;
|
||||
|
||||
|
@ -10,10 +10,9 @@ namespace VideoCore {
|
||||
|
||||
FramebufferBase::FramebufferBase() = default;
|
||||
|
||||
FramebufferBase::FramebufferBase(const Pica::Regs& regs, SurfaceBase* const color_,
|
||||
SurfaceBase* const depth_stencil_,
|
||||
Common::Rectangle<u32> surfaces_rect)
|
||||
: color{color_}, depth_stencil{depth_stencil_} {
|
||||
FramebufferBase::FramebufferBase(const Pica::Regs& regs, SurfaceBase* const color,
|
||||
SurfaceBase* const depth_stencil,
|
||||
Common::Rectangle<u32> surfaces_rect) {
|
||||
res_scale = color ? color->res_scale : (depth_stencil ? depth_stencil->res_scale : 1u);
|
||||
|
||||
// Determine the draw rectangle (render area + scissor)
|
||||
@ -54,9 +53,11 @@ FramebufferBase::FramebufferBase(const Pica::Regs& regs, SurfaceBase* const colo
|
||||
// Query surface invalidation intervals
|
||||
const Common::Rectangle draw_rect_unscaled{draw_rect / res_scale};
|
||||
if (color) {
|
||||
color_params = *color;
|
||||
intervals[0] = color->GetSubRectInterval(draw_rect_unscaled);
|
||||
}
|
||||
if (depth_stencil) {
|
||||
depth_params = *depth_stencil;
|
||||
intervals[1] = depth_stencil->GetSubRectInterval(draw_rect_unscaled);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/math_util.h"
|
||||
#include "video_core/rasterizer_cache/utils.h"
|
||||
#include "video_core/rasterizer_cache/surface_params.h"
|
||||
|
||||
namespace Pica {
|
||||
struct Regs;
|
||||
@ -32,12 +32,12 @@ public:
|
||||
FramebufferBase(const Pica::Regs& regs, SurfaceBase* const color,
|
||||
SurfaceBase* const depth_stencil, Common::Rectangle<u32> surfaces_rect);
|
||||
|
||||
SurfaceBase* Color() const noexcept {
|
||||
return color;
|
||||
SurfaceParams ColorParams() const noexcept {
|
||||
return color_params;
|
||||
}
|
||||
|
||||
SurfaceBase* DepthStencil() const noexcept {
|
||||
return depth_stencil;
|
||||
SurfaceParams DepthParams() const noexcept {
|
||||
return depth_params;
|
||||
}
|
||||
|
||||
SurfaceInterval Interval(SurfaceType type) const noexcept {
|
||||
@ -74,8 +74,8 @@ protected:
|
||||
}
|
||||
|
||||
protected:
|
||||
SurfaceBase* color{};
|
||||
SurfaceBase* depth_stencil{};
|
||||
SurfaceParams color_params{};
|
||||
SurfaceParams depth_params{};
|
||||
std::array<SurfaceInterval, 2> intervals{};
|
||||
Common::Rectangle<s32> scissor_rect{};
|
||||
Common::Rectangle<u32> draw_rect{};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -46,21 +46,21 @@ class RasterizerCache : NonCopyable {
|
||||
static constexpr u64 CITRA_PAGEBITS = 18;
|
||||
|
||||
using Runtime = typename T::Runtime;
|
||||
using Surface = std::shared_ptr<typename T::Surface>;
|
||||
using Surface = typename T::Surface;
|
||||
using Sampler = typename T::Sampler;
|
||||
using Framebuffer = typename T::Framebuffer;
|
||||
|
||||
/// Declare rasterizer interval types
|
||||
using SurfaceMap = boost::icl::interval_map<PAddr, Surface, boost::icl::partial_absorber,
|
||||
using SurfaceMap = boost::icl::interval_map<PAddr, SurfaceId, boost::icl::partial_absorber,
|
||||
std::less, boost::icl::inplace_plus,
|
||||
boost::icl::inter_section, SurfaceInterval>;
|
||||
|
||||
using SurfaceRect_Tuple = std::tuple<Surface, Common::Rectangle<u32>>;
|
||||
using SurfaceRect_Tuple = std::pair<SurfaceId, Common::Rectangle<u32>>;
|
||||
using PageMap = boost::icl::interval_map<u32, int>;
|
||||
|
||||
struct RenderTargets {
|
||||
Surface color_surface;
|
||||
Surface depth_surface;
|
||||
SurfaceId color_surface_id;
|
||||
SurfaceId depth_surface_id;
|
||||
};
|
||||
|
||||
public:
|
||||
@ -77,17 +77,19 @@ public:
|
||||
/// Perform hardware accelerated memory fill according to the provided configuration
|
||||
bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config);
|
||||
|
||||
/// Returns a reference to the surface object assigned to surface_id
|
||||
Surface& GetSurface(SurfaceId surface_id);
|
||||
|
||||
/// Returns a reference to the sampler object matching the provided configuration
|
||||
Sampler& GetSampler(const Pica::TexturingRegs::TextureConfig& config);
|
||||
Sampler& GetSampler(SamplerId sampler_id);
|
||||
|
||||
/// Copy one surface's region to another
|
||||
void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
SurfaceInterval copy_interval);
|
||||
void CopySurface(Surface& src_surface, Surface& dst_surface, SurfaceInterval copy_interval);
|
||||
|
||||
/// Load a texture from 3DS memory to OpenGL and cache it (if not already cached)
|
||||
Surface GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale,
|
||||
bool load_if_create);
|
||||
SurfaceId GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale,
|
||||
bool load_if_create);
|
||||
|
||||
/// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from
|
||||
/// 3DS memory to OpenGL and caches it (if not already cached)
|
||||
@ -95,11 +97,11 @@ public:
|
||||
bool load_if_create);
|
||||
|
||||
/// Get a surface based on the texture configuration
|
||||
Surface GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config);
|
||||
Surface GetTextureSurface(const Pica::Texture::TextureInfo& info, u32 max_level = 0);
|
||||
Surface& GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config);
|
||||
Surface& GetTextureSurface(const Pica::Texture::TextureInfo& info, u32 max_level = 0);
|
||||
|
||||
/// Get a texture cube based on the texture configuration
|
||||
const Surface& GetTextureCube(const TextureCubeConfig& config);
|
||||
Surface& GetTextureCube(const TextureCubeConfig& config);
|
||||
|
||||
/// Get the color and depth surfaces based on the framebuffer configuration
|
||||
Framebuffer GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb);
|
||||
@ -111,10 +113,10 @@ public:
|
||||
SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params);
|
||||
|
||||
/// Write any cached resources overlapping the region back to memory (if dirty)
|
||||
void FlushRegion(PAddr addr, u32 size, Surface flush_surface = nullptr);
|
||||
void FlushRegion(PAddr addr, u32 size, SurfaceId flush_surface_id = {});
|
||||
|
||||
/// Mark region as being invalidated by region_owner (nullptr if 3DS memory)
|
||||
void InvalidateRegion(PAddr addr, u32 size, const Surface& region_owner);
|
||||
void InvalidateRegion(PAddr addr, u32 size, SurfaceId region_owner_id = {});
|
||||
|
||||
/// Flush all cached resources tracked by this cache manager
|
||||
void FlushAll();
|
||||
@ -145,47 +147,47 @@ private:
|
||||
|
||||
/// Get the best surface match (and its match type) for the given flags
|
||||
template <MatchFlags find_flags>
|
||||
Surface FindMatch(const SurfaceParams& params, ScaleMatch match_scale_type,
|
||||
std::optional<SurfaceInterval> validate_interval = std::nullopt);
|
||||
SurfaceId FindMatch(const SurfaceParams& params, ScaleMatch match_scale_type,
|
||||
std::optional<SurfaceInterval> validate_interval = std::nullopt);
|
||||
|
||||
/// Duplicates src_surface contents to dest_surface
|
||||
void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface);
|
||||
void DuplicateSurface(SurfaceId src_id, SurfaceId dst_id);
|
||||
|
||||
/// Update surface's texture for given region when necessary
|
||||
void ValidateSurface(const Surface& surface, PAddr addr, u32 size);
|
||||
void ValidateSurface(SurfaceId surface_id, PAddr addr, u32 size);
|
||||
|
||||
/// Copies pixel data in interval from the guest VRAM to the host GPU surface
|
||||
void UploadSurface(const Surface& surface, SurfaceInterval interval);
|
||||
void UploadSurface(Surface& surface, SurfaceInterval interval);
|
||||
|
||||
/// Uploads a custom texture associated with upload_data to the target surface
|
||||
bool UploadCustomSurface(const Surface& surface, const SurfaceParams& load_info,
|
||||
bool UploadCustomSurface(Surface& surface, const SurfaceParams& load_info,
|
||||
std::span<u8> upload_data);
|
||||
|
||||
/// Copies pixel data in interval from the host GPU surface to the guest VRAM
|
||||
void DownloadSurface(const Surface& surface, SurfaceInterval interval);
|
||||
void DownloadSurface(Surface& surface, SurfaceInterval interval);
|
||||
|
||||
/// Downloads a fill surface to guest VRAM
|
||||
void DownloadFillSurface(const Surface& surface, SurfaceInterval interval);
|
||||
void DownloadFillSurface(Surface& surface, SurfaceInterval interval);
|
||||
|
||||
/// Returns false if there is a surface in the cache at the interval with the same bit-width,
|
||||
bool NoUnimplementedReinterpretations(const Surface& surface, SurfaceParams params,
|
||||
bool NoUnimplementedReinterpretations(Surface& surface, SurfaceParams params,
|
||||
SurfaceInterval interval);
|
||||
|
||||
/// Return true if a surface with an invalid pixel format exists at the interval
|
||||
bool IntervalHasInvalidPixelFormat(SurfaceParams params, SurfaceInterval interval);
|
||||
bool IntervalHasInvalidPixelFormat(const SurfaceParams params, SurfaceInterval interval);
|
||||
|
||||
/// Attempt to find a reinterpretable surface in the cache and use it to copy for validation
|
||||
bool ValidateByReinterpretation(const Surface& surface, SurfaceParams params,
|
||||
bool ValidateByReinterpretation(Surface& surface, SurfaceParams params,
|
||||
SurfaceInterval interval);
|
||||
|
||||
/// Create a new surface
|
||||
Surface CreateSurface(SurfaceParams& params);
|
||||
SurfaceId CreateSurface(const SurfaceParams& params);
|
||||
|
||||
/// Register surface into the cache
|
||||
void RegisterSurface(const Surface& surface);
|
||||
void RegisterSurface(SurfaceId surface_id);
|
||||
|
||||
/// Remove surface from the cache
|
||||
void UnregisterSurface(const Surface& surface);
|
||||
void UnregisterSurface(SurfaceId surface_id);
|
||||
|
||||
/// Unregisters all surfaces from the cache
|
||||
void UnregisterAll();
|
||||
@ -199,16 +201,17 @@ private:
|
||||
CustomTexManager& custom_tex_manager;
|
||||
PageMap cached_pages;
|
||||
SurfaceMap dirty_regions;
|
||||
std::vector<Surface> remove_surfaces;
|
||||
std::vector<SurfaceId> remove_surfaces;
|
||||
u16 resolution_scale_factor;
|
||||
std::unordered_map<TextureCubeConfig, Surface> texture_cube_cache;
|
||||
std::unordered_map<TextureCubeConfig, SurfaceId> texture_cube_cache;
|
||||
|
||||
// The internal surface cache is based on buckets of 256KB.
|
||||
// This fits better for the purpose of this cache as textures are normaly
|
||||
// large in size.
|
||||
std::unordered_map<u64, std::vector<Surface>, Common::IdentityHash<u64>> page_table;
|
||||
std::unordered_map<u64, std::vector<SurfaceId>, Common::IdentityHash<u64>> page_table;
|
||||
std::unordered_map<SamplerParams, SamplerId> samplers;
|
||||
|
||||
SlotVector<Surface> slot_surfaces;
|
||||
SlotVector<Sampler> slot_samplers;
|
||||
RenderTargets render_targets;
|
||||
|
||||
|
@ -20,8 +20,7 @@ public:
|
||||
/// Returns true when this surface can be used to fill the fill_interval of dest_surface
|
||||
bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const;
|
||||
|
||||
/// Returns true when copy_interval of dest_surface can be validated by copying from this
|
||||
/// surface
|
||||
/// Returns true when surface can validate copy_interval of dest_surface
|
||||
bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const;
|
||||
|
||||
/// Returns the region of the biggest valid rectange within interval
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
#include "video_core/rasterizer_cache/utils.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
@ -10,46 +10,10 @@
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
ClearValue MakeClearValue(SurfaceType type, PixelFormat format, const u8* fill_data) {
|
||||
ClearValue result{};
|
||||
switch (type) {
|
||||
case SurfaceType::Color:
|
||||
case SurfaceType::Texture:
|
||||
case SurfaceType::Fill: {
|
||||
Pica::Texture::TextureInfo tex_info{};
|
||||
tex_info.format = static_cast<Pica::TexturingRegs::TextureFormat>(format);
|
||||
const auto color = Pica::Texture::LookupTexture(fill_data, 0, 0, tex_info);
|
||||
result.color = color / 255.f;
|
||||
break;
|
||||
}
|
||||
case SurfaceType::Depth: {
|
||||
u32 depth_uint = 0;
|
||||
if (format == PixelFormat::D16) {
|
||||
std::memcpy(&depth_uint, fill_data, 2);
|
||||
result.depth = depth_uint / 65535.0f; // 2^16 - 1
|
||||
} else if (format == PixelFormat::D24) {
|
||||
std::memcpy(&depth_uint, fill_data, 3);
|
||||
result.depth = depth_uint / 16777215.0f; // 2^24 - 1
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SurfaceType::DepthStencil: {
|
||||
u32 clear_value_uint;
|
||||
std::memcpy(&clear_value_uint, fill_data, sizeof(u32));
|
||||
result.depth = (clear_value_uint & 0xFFFFFF) / 16777215.0f; // 2^24 - 1
|
||||
result.stencil = (clear_value_uint >> 24);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid surface type!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void EncodeTexture(const SurfaceParams& surface_info, PAddr start_addr, PAddr end_addr,
|
||||
std::span<u8> source, std::span<u8> dest, bool convert) {
|
||||
const u32 func_index = static_cast<u32>(surface_info.pixel_format);
|
||||
const PixelFormat format = surface_info.pixel_format;
|
||||
const u32 func_index = static_cast<u32>(format);
|
||||
|
||||
if (surface_info.is_tiled) {
|
||||
const MortonFunc SwizzleImpl =
|
||||
@ -87,7 +51,8 @@ u32 MipLevels(u32 width, u32 height, u32 max_level) {
|
||||
|
||||
void DecodeTexture(const SurfaceParams& surface_info, PAddr start_addr, PAddr end_addr,
|
||||
std::span<u8> source, std::span<u8> dest, bool convert) {
|
||||
const u32 func_index = static_cast<u32>(surface_info.pixel_format);
|
||||
const PixelFormat format = surface_info.pixel_format;
|
||||
const u32 func_index = static_cast<u32>(format);
|
||||
|
||||
if (surface_info.is_tiled) {
|
||||
const MortonFunc UnswizzleImpl =
|
||||
|
@ -9,15 +9,18 @@
|
||||
#include "common/hash.h"
|
||||
#include "common/math_util.h"
|
||||
#include "common/vector_math.h"
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
#include "video_core/rasterizer_cache/slot_vector.h"
|
||||
#include "video_core/regs_texturing.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
using Rect2D = Common::Rectangle<u32>;
|
||||
|
||||
using SurfaceId = SlotId;
|
||||
using SamplerId = SlotId;
|
||||
|
||||
/// Fake surface ID for null surfaces
|
||||
constexpr SurfaceId NULL_SURFACE_ID{0};
|
||||
/// Fake sampler ID for null samplers
|
||||
constexpr SamplerId NULL_SAMPLER_ID{0};
|
||||
|
||||
@ -103,8 +106,6 @@ struct TextureCubeConfig {
|
||||
|
||||
class SurfaceParams;
|
||||
|
||||
[[nodiscard]] ClearValue MakeClearValue(SurfaceType type, PixelFormat format, const u8* fill_data);
|
||||
|
||||
u32 MipLevels(u32 width, u32 height, u32 max_level);
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
#include "video_core/rasterizer_cache/utils.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
|
||||
|
@ -52,13 +52,6 @@ RasterizerOpenGL::RasterizerOpenGL(Memory::MemorySystem& memory,
|
||||
// Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
|
||||
state.clip_distance[0] = true;
|
||||
|
||||
// Create a 1x1 clear texture to use in the NULL case,
|
||||
// instead of OpenGL's default of solid black
|
||||
default_texture.Create();
|
||||
// For some reason alpha 0 wraps around to 1.0, so use 1/255 instead
|
||||
u8 framebuffer_data[4] = {0, 0, 0, 1};
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data);
|
||||
|
||||
// Generate VAO
|
||||
sw_vao.Create();
|
||||
hw_vao.Create();
|
||||
@ -212,7 +205,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset,
|
||||
u32 vertex_num = vs_input_index_max - vs_input_index_min + 1;
|
||||
u32 data_size = loader.byte_count * vertex_num;
|
||||
|
||||
res_cache.FlushRegion(data_addr, data_size, nullptr);
|
||||
res_cache.FlushRegion(data_addr, data_size);
|
||||
std::memcpy(array_ptr, memory.GetPhysicalPointer(data_addr), data_size);
|
||||
|
||||
array_ptr += data_size;
|
||||
@ -409,95 +402,8 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
||||
uniform_block_data.dirty = true;
|
||||
}
|
||||
|
||||
const auto BindCubeFace = [&](GLuint& target, Pica::TexturingRegs::CubeFace face,
|
||||
Pica::Texture::TextureInfo& info) {
|
||||
info.physical_address = regs.texturing.GetCubePhysicalAddress(face);
|
||||
auto surface = res_cache.GetTextureSurface(info);
|
||||
|
||||
if (surface != nullptr) {
|
||||
target = surface->Handle();
|
||||
} else {
|
||||
target = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Sync and bind the texture surfaces
|
||||
const auto pica_textures = regs.texturing.GetTextures();
|
||||
for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
|
||||
const auto& texture = pica_textures[texture_index];
|
||||
|
||||
if (texture.enabled) {
|
||||
Sampler& sampler = res_cache.GetSampler(texture.config);
|
||||
if (texture_index == 0) {
|
||||
using TextureType = Pica::TexturingRegs::TextureConfig::TextureType;
|
||||
switch (texture.config.type.Value()) {
|
||||
case TextureType::Shadow2D: {
|
||||
const auto surface = res_cache.GetTextureSurface(texture);
|
||||
if (surface) {
|
||||
state.image_shadow_texture_px = surface->Handle();
|
||||
} else {
|
||||
state.image_shadow_texture_px = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case TextureType::ShadowCube: {
|
||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||
auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config,
|
||||
texture.format);
|
||||
BindCubeFace(state.image_shadow_texture_px, CubeFace::PositiveX, info);
|
||||
BindCubeFace(state.image_shadow_texture_nx, CubeFace::NegativeX, info);
|
||||
BindCubeFace(state.image_shadow_texture_py, CubeFace::PositiveY, info);
|
||||
BindCubeFace(state.image_shadow_texture_ny, CubeFace::NegativeY, info);
|
||||
BindCubeFace(state.image_shadow_texture_pz, CubeFace::PositiveZ, info);
|
||||
BindCubeFace(state.image_shadow_texture_nz, CubeFace::NegativeZ, info);
|
||||
continue;
|
||||
}
|
||||
case TextureType::TextureCube: {
|
||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||
const VideoCore::TextureCubeConfig config = {
|
||||
.px = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveX),
|
||||
.nx = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeX),
|
||||
.py = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveY),
|
||||
.ny = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeY),
|
||||
.pz = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ),
|
||||
.nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ),
|
||||
.width = texture.config.width,
|
||||
.levels = texture.config.lod.max_level + 1,
|
||||
.format = texture.format};
|
||||
|
||||
state.texture_cube_unit.texture_cube =
|
||||
res_cache.GetTextureCube(config)->Handle();
|
||||
|
||||
state.texture_cube_unit.sampler = sampler.Handle();
|
||||
state.texture_units[texture_index].texture_2d = 0;
|
||||
continue; // Texture unit 0 setup finished. Continue to next unit
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
state.texture_cube_unit.texture_cube = 0;
|
||||
}
|
||||
|
||||
state.texture_units[texture_index].sampler = sampler.Handle();
|
||||
|
||||
auto surface = res_cache.GetTextureSurface(texture);
|
||||
if (surface != nullptr) {
|
||||
state.texture_units[texture_index].texture_2d = surface->Handle();
|
||||
} else {
|
||||
// Can occur when texture addr is null or its memory is unmapped/invalid
|
||||
// HACK: In this case, the correct behaviour for the PICA is to use the last
|
||||
// rendered colour. But because this would be impractical to implement, the
|
||||
// next best alternative is to use a clear texture, essentially skipping
|
||||
// the geometry in question.
|
||||
// For example: a bug in Pokemon X/Y causes NULL-texture squares to be drawn
|
||||
// on the male character's face, which in the OpenGL default appear black.
|
||||
state.texture_units[texture_index].texture_2d = default_texture.handle;
|
||||
}
|
||||
} else {
|
||||
state.texture_units[texture_index].texture_2d = 0;
|
||||
}
|
||||
}
|
||||
SyncTextureUnits(framebuffer);
|
||||
|
||||
// Sync and bind the shader
|
||||
if (shader_dirty) {
|
||||
@ -562,6 +468,114 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncTextureUnits(const Framebuffer& framebuffer) {
|
||||
using TextureType = Pica::TexturingRegs::TextureConfig::TextureType;
|
||||
|
||||
const auto pica_textures = regs.texturing.GetTextures();
|
||||
for (u32 texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
|
||||
const auto& texture = pica_textures[texture_index];
|
||||
|
||||
// If the texture unit is disabled unbind the corresponding gl unit
|
||||
if (!texture.enabled) {
|
||||
state.texture_units[texture_index].texture_2d = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle special tex0 configurations
|
||||
if (texture_index == 0) {
|
||||
switch (texture.config.type.Value()) {
|
||||
case TextureType::Shadow2D: {
|
||||
Surface& surface = res_cache.GetTextureSurface(texture);
|
||||
state.image_shadow_texture_px = surface.Handle();
|
||||
continue;
|
||||
}
|
||||
case TextureType::ShadowCube: {
|
||||
BindShadowCube(texture);
|
||||
continue;
|
||||
}
|
||||
case TextureType::TextureCube: {
|
||||
BindTextureCube(texture);
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Bind texture unit sampler
|
||||
Sampler& sampler = res_cache.GetSampler(texture.config);
|
||||
state.texture_units[texture_index].sampler = sampler.Handle();
|
||||
|
||||
// Bind the texture provided by the rasterizer cache
|
||||
Surface& surface = res_cache.GetTextureSurface(texture);
|
||||
if (!IsFeedbackLoop(texture_index, framebuffer, surface)) {
|
||||
state.texture_units[texture_index].texture_2d = surface.Handle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::BindShadowCube(const Pica::TexturingRegs::FullTextureConfig& texture) {
|
||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||
auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
|
||||
constexpr std::array faces = {
|
||||
CubeFace::PositiveX, CubeFace::NegativeX, CubeFace::PositiveY,
|
||||
CubeFace::NegativeY, CubeFace::PositiveZ, CubeFace::NegativeZ,
|
||||
};
|
||||
|
||||
for (CubeFace face : faces) {
|
||||
const u32 binding = static_cast<u32>(face);
|
||||
info.physical_address = regs.texturing.GetCubePhysicalAddress(face);
|
||||
|
||||
Surface& surface = res_cache.GetTextureSurface(info);
|
||||
state.image_shadow_texture[binding] = surface.Handle();
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::BindTextureCube(const Pica::TexturingRegs::FullTextureConfig& texture) {
|
||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||
const VideoCore::TextureCubeConfig config = {
|
||||
.px = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveX),
|
||||
.nx = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeX),
|
||||
.py = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveY),
|
||||
.ny = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeY),
|
||||
.pz = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ),
|
||||
.nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ),
|
||||
.width = texture.config.width,
|
||||
.levels = texture.config.lod.max_level + 1,
|
||||
.format = texture.format,
|
||||
};
|
||||
|
||||
Surface& surface = res_cache.GetTextureCube(config);
|
||||
Sampler& sampler = res_cache.GetSampler(texture.config);
|
||||
state.texture_cube_unit.texture_cube = surface.Handle();
|
||||
state.texture_cube_unit.sampler = sampler.Handle();
|
||||
state.texture_units[0].texture_2d = 0;
|
||||
}
|
||||
|
||||
bool RasterizerOpenGL::IsFeedbackLoop(u32 texture_index, const Framebuffer& framebuffer,
|
||||
Surface& surface) {
|
||||
const GLuint color_attachment = framebuffer.Attachment(SurfaceType::Color);
|
||||
const bool is_feedback_loop = color_attachment == surface.Handle();
|
||||
if (!is_feedback_loop) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make a temporary copy of the framebuffer to sample from
|
||||
Surface temp_surface{runtime, framebuffer.ColorParams()};
|
||||
const VideoCore::TextureCopy copy = {
|
||||
.src_level = 0,
|
||||
.dst_level = 0,
|
||||
.src_layer = 0,
|
||||
.dst_layer = 0,
|
||||
.src_offset = {0, 0},
|
||||
.dst_offset = {0, 0},
|
||||
.extent = {temp_surface.GetScaledWidth(), temp_surface.GetScaledHeight()},
|
||||
};
|
||||
runtime.CopyTextures(surface, temp_surface, copy);
|
||||
state.texture_units[texture_index].texture_2d = temp_surface.Handle();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::NotifyFixedFunctionPicaRegisterChanged(u32 id) {
|
||||
switch (id) {
|
||||
// Clipping plane
|
||||
@ -641,13 +655,13 @@ void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
|
||||
|
||||
void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) {
|
||||
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
||||
res_cache.InvalidateRegion(addr, size, nullptr);
|
||||
res_cache.InvalidateRegion(addr, size);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
|
||||
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
||||
res_cache.FlushRegion(addr, size);
|
||||
res_cache.InvalidateRegion(addr, size, nullptr);
|
||||
res_cache.InvalidateRegion(addr, size);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::ClearAll(bool flush) {
|
||||
@ -684,21 +698,22 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
|
||||
src_params.pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(config.color_format);
|
||||
src_params.UpdateParams();
|
||||
|
||||
const auto [src_surface, src_rect] =
|
||||
const auto [src_surface_id, src_rect] =
|
||||
res_cache.GetSurfaceSubRect(src_params, VideoCore::ScaleMatch::Ignore, true);
|
||||
|
||||
if (src_surface == nullptr) {
|
||||
if (!src_surface_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 scaled_width = src_surface->GetScaledWidth();
|
||||
const u32 scaled_height = src_surface->GetScaledHeight();
|
||||
Surface& src_surface = res_cache.GetSurface(src_surface_id);
|
||||
const u32 scaled_width = src_surface.GetScaledWidth();
|
||||
const u32 scaled_height = src_surface.GetScaledHeight();
|
||||
|
||||
screen_info.display_texcoords = Common::Rectangle<float>(
|
||||
(float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
|
||||
(float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
|
||||
|
||||
screen_info.display_texture = src_surface->Handle();
|
||||
screen_info.display_texture = src_surface.Handle();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -94,6 +94,18 @@ private:
|
||||
void SyncAndUploadLUTs();
|
||||
void SyncAndUploadLUTsLF();
|
||||
|
||||
/// Syncs all enabled PICA texture units
|
||||
void SyncTextureUnits(const Framebuffer& framebuffer);
|
||||
|
||||
/// Binds the PICA shadow cube required for shadow mapping
|
||||
void BindShadowCube(const Pica::TexturingRegs::FullTextureConfig& texture);
|
||||
|
||||
/// Binds a texture cube to texture unit 0
|
||||
void BindTextureCube(const Pica::TexturingRegs::FullTextureConfig& texture);
|
||||
|
||||
/// Makes a temporary copy of the framebuffer if a feedback loop is detected
|
||||
bool IsFeedbackLoop(u32 texture_index, const Framebuffer& framebuffer, Surface& surface);
|
||||
|
||||
/// Upload the uniform blocks to the uniform buffer object
|
||||
void UploadUniforms(bool accelerate_draw);
|
||||
|
||||
@ -124,7 +136,6 @@ private:
|
||||
OGLVertexArray hw_vao; // VAO for hardware shader / accelerate draw
|
||||
std::array<bool, 16> hw_vao_enabled_attributes{};
|
||||
|
||||
OGLTexture default_texture;
|
||||
StreamBuffer vertex_buffer;
|
||||
StreamBuffer uniform_buffer;
|
||||
StreamBuffer index_buffer;
|
||||
|
@ -116,12 +116,17 @@ public:
|
||||
|
||||
// GL_IMAGE_BINDING_NAME
|
||||
GLuint image_shadow_buffer;
|
||||
GLuint image_shadow_texture_px;
|
||||
GLuint image_shadow_texture_nx;
|
||||
GLuint image_shadow_texture_py;
|
||||
GLuint image_shadow_texture_ny;
|
||||
GLuint image_shadow_texture_pz;
|
||||
GLuint image_shadow_texture_nz;
|
||||
union {
|
||||
std::array<GLuint, 6> image_shadow_texture;
|
||||
struct {
|
||||
GLuint image_shadow_texture_px;
|
||||
GLuint image_shadow_texture_nx;
|
||||
GLuint image_shadow_texture_py;
|
||||
GLuint image_shadow_texture_ny;
|
||||
GLuint image_shadow_texture_pz;
|
||||
GLuint image_shadow_texture_nz;
|
||||
};
|
||||
};
|
||||
|
||||
struct {
|
||||
GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
|
||||
|
@ -332,16 +332,16 @@ void TextureRuntime::BindFramebuffer(GLenum target, GLint level, GLenum textarge
|
||||
}
|
||||
}
|
||||
|
||||
Surface::Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime)
|
||||
: VideoCore::SurfaceBase{params}, runtime{runtime}, driver{runtime.GetDriver()} {
|
||||
Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceParams& params)
|
||||
: VideoCore::SurfaceBase{params}, runtime{&runtime_}, driver{&runtime_.GetDriver()} {
|
||||
if (pixel_format != VideoCore::PixelFormat::Invalid) {
|
||||
const auto& tuple = runtime.GetFormatTuple(pixel_format);
|
||||
alloc = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), levels, tuple, texture_type);
|
||||
const auto& tuple = runtime->GetFormatTuple(pixel_format);
|
||||
alloc = runtime->Allocate(GetScaledWidth(), GetScaledHeight(), levels, tuple, texture_type);
|
||||
}
|
||||
}
|
||||
|
||||
Surface::~Surface() {
|
||||
if (pixel_format == VideoCore::PixelFormat::Invalid) {
|
||||
if (pixel_format == VideoCore::PixelFormat::Invalid || !Handle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -352,7 +352,7 @@ Surface::~Surface() {
|
||||
.height = alloc.height,
|
||||
.levels = alloc.levels,
|
||||
};
|
||||
runtime.Recycle(tag, std::move(alloc));
|
||||
runtime->Recycle(tag, std::move(alloc));
|
||||
}
|
||||
|
||||
void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) {
|
||||
@ -398,10 +398,10 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
|
||||
const VideoCore::Rect2D rect = download.texture_rect;
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(rect.GetWidth()));
|
||||
|
||||
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type,
|
||||
Handle());
|
||||
runtime->BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type,
|
||||
Handle());
|
||||
|
||||
const auto& tuple = runtime.GetFormatTuple(pixel_format);
|
||||
const auto& tuple = runtime->GetFormatTuple(pixel_format);
|
||||
glReadPixels(rect.left, rect.bottom, rect.GetWidth(), rect.GetHeight(), tuple.format,
|
||||
tuple.type, staging.mapped.data());
|
||||
|
||||
@ -413,11 +413,11 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
|
||||
}
|
||||
|
||||
bool Surface::Swap(u32 width, u32 height, VideoCore::CustomPixelFormat format) {
|
||||
if (!driver.IsCustomFormatSupported(format)) {
|
||||
if (!driver->IsCustomFormatSupported(format)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& tuple = runtime.GetFormatTuple(format);
|
||||
const auto& tuple = runtime->GetFormatTuple(format);
|
||||
if (alloc.Matches(width, height, levels, tuple)) {
|
||||
return true;
|
||||
}
|
||||
@ -429,11 +429,11 @@ bool Surface::Swap(u32 width, u32 height, VideoCore::CustomPixelFormat format) {
|
||||
.height = alloc.height,
|
||||
.levels = alloc.levels,
|
||||
};
|
||||
runtime.Recycle(tag, std::move(alloc));
|
||||
runtime->Recycle(tag, std::move(alloc));
|
||||
|
||||
is_custom = true;
|
||||
custom_format = format;
|
||||
alloc = runtime.Allocate(width, height, levels, tuple, texture_type);
|
||||
alloc = runtime->Allocate(width, height, levels, tuple, texture_type);
|
||||
|
||||
LOG_DEBUG(Render_OpenGL, "Swapped {}x{} {} surface at address {:#x} to {}x{} {}",
|
||||
GetScaledWidth(), GetScaledHeight(), VideoCore::PixelFormatAsString(pixel_format),
|
||||
@ -453,7 +453,7 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const Sta
|
||||
unscaled_params.stride = rect_width;
|
||||
unscaled_params.height = rect_height;
|
||||
unscaled_params.res_scale = 1;
|
||||
Surface unscaled_surface{unscaled_params, runtime};
|
||||
Surface unscaled_surface{*runtime, unscaled_params};
|
||||
|
||||
const VideoCore::BufferTextureCopy unscaled_upload = {
|
||||
.buffer_offset = upload.buffer_offset,
|
||||
@ -462,7 +462,7 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const Sta
|
||||
};
|
||||
unscaled_surface.Upload(unscaled_upload, staging);
|
||||
|
||||
const auto& filterer = runtime.GetFilterer();
|
||||
const auto& filterer = runtime->GetFilterer();
|
||||
if (!filterer.Filter(unscaled_surface.alloc.texture, unscaled_rect, alloc.texture, scaled_rect,
|
||||
type)) {
|
||||
const VideoCore::TextureBlit blit = {
|
||||
@ -471,7 +471,7 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const Sta
|
||||
.src_rect = unscaled_rect,
|
||||
.dst_rect = scaled_rect,
|
||||
};
|
||||
runtime.BlitTextures(unscaled_surface, *this, blit);
|
||||
runtime->BlitTextures(unscaled_surface, *this, blit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -488,7 +488,7 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
|
||||
unscaled_params.stride = rect_width;
|
||||
unscaled_params.height = rect_height;
|
||||
unscaled_params.res_scale = 1;
|
||||
Surface unscaled_surface{unscaled_params, runtime};
|
||||
Surface unscaled_surface{*runtime, unscaled_params};
|
||||
|
||||
// Blit the scaled rectangle to the unscaled texture
|
||||
const VideoCore::TextureBlit blit = {
|
||||
@ -499,15 +499,15 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
|
||||
.src_rect = scaled_rect,
|
||||
.dst_rect = unscaled_rect,
|
||||
};
|
||||
runtime.BlitTextures(*this, unscaled_surface, blit);
|
||||
runtime->BlitTextures(*this, unscaled_surface, blit);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, unscaled_surface.Handle());
|
||||
|
||||
const auto& tuple = runtime.GetFormatTuple(pixel_format);
|
||||
if (driver.IsOpenGLES()) {
|
||||
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type,
|
||||
unscaled_surface.Handle());
|
||||
const auto& tuple = runtime->GetFormatTuple(pixel_format);
|
||||
if (driver->IsOpenGLES()) {
|
||||
runtime->BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type,
|
||||
unscaled_surface.Handle());
|
||||
glReadPixels(0, 0, rect_width, rect_height, tuple.format, tuple.type,
|
||||
staging.mapped.data());
|
||||
} else {
|
||||
|
@ -153,9 +153,15 @@ private:
|
||||
|
||||
class Surface : public VideoCore::SurfaceBase {
|
||||
public:
|
||||
explicit Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime);
|
||||
explicit Surface(TextureRuntime& runtime, const VideoCore::SurfaceParams& params);
|
||||
~Surface();
|
||||
|
||||
Surface(const Surface&) = delete;
|
||||
Surface& operator=(const Surface&) = delete;
|
||||
|
||||
Surface(Surface&& o) noexcept = default;
|
||||
Surface& operator=(Surface&& o) noexcept = default;
|
||||
|
||||
/// Returns the surface image handle
|
||||
GLuint Handle() const noexcept {
|
||||
return alloc.texture.handle;
|
||||
@ -186,9 +192,9 @@ private:
|
||||
const VideoCore::StagingData& staging);
|
||||
|
||||
private:
|
||||
TextureRuntime& runtime;
|
||||
const Driver& driver;
|
||||
Allocation alloc;
|
||||
TextureRuntime* runtime;
|
||||
const Driver* driver;
|
||||
Allocation alloc{};
|
||||
};
|
||||
|
||||
class Framebuffer : public VideoCore::FramebufferBase {
|
||||
|
@ -13,7 +13,6 @@
|
||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
||||
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||
#define VULKAN_HPP_NO_STRUCT_SETTERS
|
||||
#define VULKAN_HPP_NO_SMART_HANDLE
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||
#include "video_core/rasterizer_cache/utils.h"
|
||||
#include "video_core/renderer_vulkan/vk_common.h"
|
||||
|
||||
|
@ -37,20 +37,6 @@ constexpr vk::BufferUsageFlags BUFFER_USAGE = vk::BufferUsageFlagBits::eVertexBu
|
||||
|
||||
constexpr vk::BufferUsageFlags TEX_BUFFER_USAGE = vk::BufferUsageFlagBits::eUniformTexelBuffer;
|
||||
|
||||
constexpr VideoCore::SurfaceParams NULL_PARAMS = {
|
||||
.width = 1,
|
||||
.height = 1,
|
||||
.stride = 1,
|
||||
.texture_type = VideoCore::TextureType::Texture2D,
|
||||
.pixel_format = VideoCore::PixelFormat::RGBA8,
|
||||
.type = VideoCore::SurfaceType::Color,
|
||||
};
|
||||
|
||||
constexpr vk::ImageUsageFlags NULL_USAGE = vk::ImageUsageFlagBits::eSampled |
|
||||
vk::ImageUsageFlagBits::eTransferSrc |
|
||||
vk::ImageUsageFlagBits::eTransferDst;
|
||||
constexpr vk::ImageUsageFlags NULL_STORAGE_USAGE = NULL_USAGE | vk::ImageUsageFlagBits::eStorage;
|
||||
|
||||
struct DrawParams {
|
||||
u32 vertex_count;
|
||||
s32 vertex_offset;
|
||||
@ -78,10 +64,6 @@ RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory,
|
||||
custom_tex_manager,
|
||||
runtime},
|
||||
pipeline_cache{instance, scheduler, renderpass_cache, desc_manager},
|
||||
null_surface{NULL_PARAMS, vk::Format::eR8G8B8A8Unorm, NULL_USAGE,
|
||||
vk::ImageAspectFlagBits::eColor, runtime},
|
||||
null_storage_surface{NULL_PARAMS, vk::Format::eR32Uint, NULL_STORAGE_USAGE,
|
||||
vk::ImageAspectFlagBits::eColor, runtime},
|
||||
stream_buffer{instance, scheduler, BUFFER_USAGE, STREAM_BUFFER_SIZE},
|
||||
texture_buffer{instance, scheduler, TEX_BUFFER_USAGE, TextureBufferSize(instance)},
|
||||
texture_lf_buffer{instance, scheduler, TEX_BUFFER_USAGE, TextureBufferSize(instance)},
|
||||
@ -127,18 +109,17 @@ RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory,
|
||||
pipeline_cache.BindTexelBuffer(3, texture_rg_view);
|
||||
pipeline_cache.BindTexelBuffer(4, texture_rgba_view);
|
||||
|
||||
const Sampler& null_sampler = res_cache.GetSampler(VideoCore::NULL_SAMPLER_ID);
|
||||
Surface& null_surface = res_cache.GetSurface(VideoCore::NULL_SURFACE_ID);
|
||||
Sampler& null_sampler = res_cache.GetSampler(VideoCore::NULL_SAMPLER_ID);
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
pipeline_cache.BindTexture(i, null_surface.ImageView(), null_sampler.Handle());
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < 7; i++) {
|
||||
pipeline_cache.BindStorageImage(i, null_storage_surface.ImageView());
|
||||
pipeline_cache.BindStorageImage(i, null_surface.StorageView());
|
||||
}
|
||||
|
||||
// Explicitly call the derived version to avoid warnings about calling virtual
|
||||
// methods in the constructor
|
||||
RasterizerVulkan::SyncEntireState();
|
||||
SyncEntireState();
|
||||
}
|
||||
|
||||
RasterizerVulkan::~RasterizerVulkan() {
|
||||
@ -566,111 +547,111 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SyncTextureUnits(const Framebuffer& framebuffer) {
|
||||
const auto pica_textures = regs.texturing.GetTextures();
|
||||
const vk::ImageView color_view = framebuffer.ImageView(SurfaceType::Color);
|
||||
using TextureType = Pica::TexturingRegs::TextureConfig::TextureType;
|
||||
|
||||
const auto pica_textures = regs.texturing.GetTextures();
|
||||
for (u32 texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
|
||||
const auto& texture = pica_textures[texture_index];
|
||||
|
||||
if (texture.enabled) {
|
||||
Sampler& sampler = res_cache.GetSampler(texture.config);
|
||||
if (texture_index == 0) {
|
||||
using TextureType = Pica::TexturingRegs::TextureConfig::TextureType;
|
||||
switch (texture.config.type.Value()) {
|
||||
case TextureType::Shadow2D: {
|
||||
auto surface = res_cache.GetTextureSurface(texture);
|
||||
if (surface) {
|
||||
pipeline_cache.BindStorageImage(0, surface->StorageView());
|
||||
} else {
|
||||
pipeline_cache.BindStorageImage(0, null_storage_surface.ImageView());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case TextureType::ShadowCube: {
|
||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||
auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config,
|
||||
texture.format);
|
||||
for (CubeFace face :
|
||||
{CubeFace::PositiveX, CubeFace::NegativeX, CubeFace::PositiveY,
|
||||
CubeFace::NegativeY, CubeFace::PositiveZ, CubeFace::NegativeZ}) {
|
||||
info.physical_address = regs.texturing.GetCubePhysicalAddress(face);
|
||||
auto surface = res_cache.GetTextureSurface(info);
|
||||
|
||||
const u32 binding = static_cast<u32>(face);
|
||||
if (surface) {
|
||||
pipeline_cache.BindStorageImage(binding, surface->ImageView());
|
||||
} else {
|
||||
pipeline_cache.BindStorageImage(binding,
|
||||
null_storage_surface.ImageView());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case TextureType::TextureCube: {
|
||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||
const VideoCore::TextureCubeConfig config = {
|
||||
.px = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveX),
|
||||
.nx = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeX),
|
||||
.py = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveY),
|
||||
.ny = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeY),
|
||||
.pz = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ),
|
||||
.nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ),
|
||||
.width = texture.config.width,
|
||||
.levels = texture.config.lod.max_level + 1,
|
||||
.format = texture.format};
|
||||
|
||||
auto surface = res_cache.GetTextureCube(config);
|
||||
if (surface) {
|
||||
pipeline_cache.BindTexture(3, surface->ImageView(), sampler.Handle());
|
||||
} else {
|
||||
pipeline_cache.BindTexture(3, null_surface.ImageView(), sampler.Handle());
|
||||
}
|
||||
continue; // Texture unit 0 setup finished. Continue to next unit
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto surface = res_cache.GetTextureSurface(texture);
|
||||
if (surface) {
|
||||
if (color_view == surface->ImageView()) {
|
||||
Surface temp{*framebuffer.Color(), runtime};
|
||||
const VideoCore::TextureCopy copy = {
|
||||
.src_level = 0,
|
||||
.dst_level = 0,
|
||||
.src_layer = 0,
|
||||
.dst_layer = 0,
|
||||
.src_offset = {0, 0},
|
||||
.dst_offset = {0, 0},
|
||||
.extent = {temp.GetScaledWidth(), temp.GetScaledHeight()},
|
||||
};
|
||||
runtime.CopyTextures(static_cast<Surface&>(*framebuffer.Color()), temp, copy);
|
||||
pipeline_cache.BindTexture(texture_index, temp.ImageView(), sampler.Handle());
|
||||
} else {
|
||||
pipeline_cache.BindTexture(texture_index, surface->ImageView(),
|
||||
sampler.Handle());
|
||||
}
|
||||
|
||||
} else {
|
||||
// Can occur when texture addr is null or its memory is unmapped/invalid
|
||||
// HACK: In this case, the correct behaviour for the PICA is to use the last
|
||||
// rendered colour. But because this would be impractical to implement, the
|
||||
// next best alternative is to use a clear texture, essentially skipping
|
||||
// the geometry in question.
|
||||
// For example: a bug in Pokemon X/Y causes NULL-texture squares to be drawn
|
||||
// on the male character's face, which in the OpenGL default appear black.
|
||||
pipeline_cache.BindTexture(texture_index, null_surface.ImageView(),
|
||||
sampler.Handle());
|
||||
}
|
||||
} else {
|
||||
// If the texture unit is disabled bind a null surface to it
|
||||
if (!texture.enabled) {
|
||||
const Surface& null_surface = res_cache.GetSurface(VideoCore::NULL_SURFACE_ID);
|
||||
const Sampler& null_sampler = res_cache.GetSampler(VideoCore::NULL_SAMPLER_ID);
|
||||
pipeline_cache.BindTexture(texture_index, null_surface.ImageView(),
|
||||
null_sampler.Handle());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle special tex0 configurations
|
||||
if (texture_index == 0) {
|
||||
switch (texture.config.type.Value()) {
|
||||
case TextureType::Shadow2D: {
|
||||
Surface& surface = res_cache.GetTextureSurface(texture);
|
||||
pipeline_cache.BindStorageImage(0, surface.StorageView());
|
||||
continue;
|
||||
}
|
||||
case TextureType::ShadowCube: {
|
||||
BindShadowCube(texture);
|
||||
continue;
|
||||
}
|
||||
case TextureType::TextureCube: {
|
||||
BindTextureCube(texture);
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Bind the texture provided by the rasterizer cache
|
||||
Surface& surface = res_cache.GetTextureSurface(texture);
|
||||
Sampler& sampler = res_cache.GetSampler(texture.config);
|
||||
if (!IsFeedbackLoop(texture_index, framebuffer, surface, sampler)) {
|
||||
pipeline_cache.BindTexture(texture_index, surface.ImageView(), sampler.Handle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::BindShadowCube(const Pica::TexturingRegs::FullTextureConfig& texture) {
|
||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||
auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
|
||||
constexpr std::array faces = {
|
||||
CubeFace::PositiveX, CubeFace::NegativeX, CubeFace::PositiveY,
|
||||
CubeFace::NegativeY, CubeFace::PositiveZ, CubeFace::NegativeZ,
|
||||
};
|
||||
|
||||
for (CubeFace face : faces) {
|
||||
const u32 binding = static_cast<u32>(face);
|
||||
info.physical_address = regs.texturing.GetCubePhysicalAddress(face);
|
||||
|
||||
Surface& surface = res_cache.GetTextureSurface(info);
|
||||
pipeline_cache.BindStorageImage(binding, surface.ImageView());
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::BindTextureCube(const Pica::TexturingRegs::FullTextureConfig& texture) {
|
||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||
const VideoCore::TextureCubeConfig config = {
|
||||
.px = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveX),
|
||||
.nx = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeX),
|
||||
.py = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveY),
|
||||
.ny = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeY),
|
||||
.pz = regs.texturing.GetCubePhysicalAddress(CubeFace::PositiveZ),
|
||||
.nz = regs.texturing.GetCubePhysicalAddress(CubeFace::NegativeZ),
|
||||
.width = texture.config.width,
|
||||
.levels = texture.config.lod.max_level + 1,
|
||||
.format = texture.format,
|
||||
};
|
||||
|
||||
Surface& surface = res_cache.GetTextureCube(config);
|
||||
Sampler& sampler = res_cache.GetSampler(texture.config);
|
||||
pipeline_cache.BindTexture(3, surface.ImageView(), sampler.Handle());
|
||||
}
|
||||
|
||||
bool RasterizerVulkan::IsFeedbackLoop(u32 texture_index, const Framebuffer& framebuffer,
|
||||
Surface& surface, Sampler& sampler) {
|
||||
const vk::ImageView color_view = framebuffer.ImageView(SurfaceType::Color);
|
||||
const bool is_feedback_loop = color_view == surface.ImageView();
|
||||
if (!is_feedback_loop) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make a temporary copy of the framebuffer to sample from
|
||||
Surface temp_surface{runtime, framebuffer.ColorParams()};
|
||||
const VideoCore::TextureCopy copy = {
|
||||
.src_level = 0,
|
||||
.dst_level = 0,
|
||||
.src_layer = 0,
|
||||
.dst_layer = 0,
|
||||
.src_offset = {0, 0},
|
||||
.dst_offset = {0, 0},
|
||||
.extent = {temp_surface.GetScaledWidth(), temp_surface.GetScaledHeight()},
|
||||
};
|
||||
runtime.CopyTextures(surface, temp_surface, copy);
|
||||
pipeline_cache.BindTexture(texture_index, temp_surface.ImageView(), sampler.Handle());
|
||||
return true;
|
||||
}
|
||||
|
||||
void RasterizerVulkan::NotifyFixedFunctionPicaRegisterChanged(u32 id) {
|
||||
switch (id) {
|
||||
// Clipping plane
|
||||
@ -750,13 +731,13 @@ void RasterizerVulkan::FlushRegion(PAddr addr, u32 size) {
|
||||
|
||||
void RasterizerVulkan::InvalidateRegion(PAddr addr, u32 size) {
|
||||
MICROPROFILE_SCOPE(Vulkan_CacheManagement);
|
||||
res_cache.InvalidateRegion(addr, size, nullptr);
|
||||
res_cache.InvalidateRegion(addr, size);
|
||||
}
|
||||
|
||||
void RasterizerVulkan::FlushAndInvalidateRegion(PAddr addr, u32 size) {
|
||||
MICROPROFILE_SCOPE(Vulkan_CacheManagement);
|
||||
res_cache.FlushRegion(addr, size);
|
||||
res_cache.InvalidateRegion(addr, size, nullptr);
|
||||
res_cache.InvalidateRegion(addr, size);
|
||||
}
|
||||
|
||||
void RasterizerVulkan::ClearAll(bool flush) {
|
||||
@ -793,21 +774,22 @@ bool RasterizerVulkan::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
|
||||
src_params.pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(config.color_format);
|
||||
src_params.UpdateParams();
|
||||
|
||||
const auto [src_surface, src_rect] =
|
||||
const auto [src_surface_id, src_rect] =
|
||||
res_cache.GetSurfaceSubRect(src_params, VideoCore::ScaleMatch::Ignore, true);
|
||||
|
||||
if (src_surface == nullptr) {
|
||||
if (!src_surface_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 scaled_width = src_surface->GetScaledWidth();
|
||||
const u32 scaled_height = src_surface->GetScaledHeight();
|
||||
const Surface& src_surface = res_cache.GetSurface(src_surface_id);
|
||||
const u32 scaled_width = src_surface.GetScaledWidth();
|
||||
const u32 scaled_height = src_surface.GetScaledHeight();
|
||||
|
||||
screen_info.texcoords = Common::Rectangle<f32>(
|
||||
(float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
|
||||
(float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
|
||||
|
||||
screen_info.image_view = src_surface->ImageView();
|
||||
screen_info.image_view = src_surface.ImageView();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -815,7 +797,10 @@ bool RasterizerVulkan::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
|
||||
void RasterizerVulkan::MakeSoftwareVertexLayout() {
|
||||
constexpr std::array sizes = {4, 4, 2, 2, 2, 1, 4, 3};
|
||||
|
||||
software_layout = VertexLayout{.binding_count = 1, .attribute_count = 8};
|
||||
software_layout = VertexLayout{
|
||||
.binding_count = 1,
|
||||
.attribute_count = 8,
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < software_layout.binding_count; i++) {
|
||||
VertexBinding& binding = software_layout.bindings[i];
|
||||
|
@ -100,6 +100,16 @@ private:
|
||||
/// Syncs all enabled PICA texture units
|
||||
void SyncTextureUnits(const Framebuffer& framebuffer);
|
||||
|
||||
/// Binds the PICA shadow cube required for shadow mapping
|
||||
void BindShadowCube(const Pica::TexturingRegs::FullTextureConfig& texture);
|
||||
|
||||
/// Binds a texture cube to texture unit 0
|
||||
void BindTextureCube(const Pica::TexturingRegs::FullTextureConfig& texture);
|
||||
|
||||
/// Makes a temporary copy of the framebuffer if a feedback loop is detected
|
||||
bool IsFeedbackLoop(u32 texture_index, const Framebuffer& framebuffer, Surface& surface,
|
||||
Sampler& sampler);
|
||||
|
||||
/// Upload the uniform blocks to the uniform buffer object
|
||||
void UploadUniforms(bool accelerate_draw);
|
||||
|
||||
@ -140,8 +150,6 @@ private:
|
||||
std::array<u32, 16> binding_offsets{};
|
||||
std::array<bool, 16> enable_attributes{};
|
||||
std::array<vk::Buffer, 16> vertex_buffers;
|
||||
Surface null_surface;
|
||||
Surface null_storage_surface;
|
||||
PipelineInfo pipeline_info;
|
||||
|
||||
StreamBuffer stream_buffer; ///< Vertex+Index+Uniform buffer
|
||||
|
@ -159,14 +159,6 @@ void TextureRuntime::Clear() {
|
||||
renderpass_cache.ClearFramebuffers();
|
||||
for (const auto& [key, alloc] : texture_recycler) {
|
||||
vmaDestroyImage(allocator, alloc.image, alloc.allocation);
|
||||
device.destroyImageView(alloc.image_view);
|
||||
if (alloc.depth_view) {
|
||||
device.destroyImageView(alloc.depth_view);
|
||||
device.destroyImageView(alloc.stencil_view);
|
||||
}
|
||||
if (alloc.storage_view) {
|
||||
device.destroyImageView(alloc.storage_view);
|
||||
}
|
||||
}
|
||||
|
||||
texture_recycler.clear();
|
||||
@ -269,7 +261,7 @@ Allocation TextureRuntime::Allocate(u32 width, u32 height, u32 levels, bool is_m
|
||||
};
|
||||
|
||||
vk::Device device = instance.GetDevice();
|
||||
const vk::ImageView image_view = device.createImageView(view_info);
|
||||
vk::UniqueImageView image_view = device.createImageViewUnique(view_info);
|
||||
|
||||
renderpass_cache.ExitRenderpass();
|
||||
scheduler.Record([image, aspect](vk::CommandBuffer cmdbuf) {
|
||||
@ -297,7 +289,7 @@ Allocation TextureRuntime::Allocate(u32 width, u32 height, u32 levels, bool is_m
|
||||
|
||||
return Allocation{
|
||||
.image = image,
|
||||
.image_view = image_view,
|
||||
.image_view = std::move(image_view),
|
||||
.allocation = allocation,
|
||||
.aspect = aspect,
|
||||
.format = format,
|
||||
@ -778,28 +770,28 @@ bool TextureRuntime::NeedsConvertion(VideoCore::PixelFormat format) const {
|
||||
traits.aspect != (vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil);
|
||||
}
|
||||
|
||||
Surface::Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime)
|
||||
: VideoCore::SurfaceBase{params}, runtime{runtime}, instance{runtime.GetInstance()},
|
||||
scheduler{runtime.GetScheduler()} {
|
||||
Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceParams& params)
|
||||
: VideoCore::SurfaceBase{params}, runtime{&runtime_}, instance{&runtime_.GetInstance()},
|
||||
scheduler{&runtime_.GetScheduler()} {
|
||||
|
||||
if (pixel_format != VideoCore::PixelFormat::Invalid) {
|
||||
alloc = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), levels, params.pixel_format,
|
||||
texture_type);
|
||||
alloc = runtime->Allocate(GetScaledWidth(), GetScaledHeight(), levels, params.pixel_format,
|
||||
texture_type);
|
||||
}
|
||||
}
|
||||
|
||||
Surface::Surface(const VideoCore::SurfaceParams& params, vk::Format format,
|
||||
vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect, TextureRuntime& runtime)
|
||||
: VideoCore::SurfaceBase{params}, runtime{runtime}, instance{runtime.GetInstance()},
|
||||
scheduler{runtime.GetScheduler()} {
|
||||
Surface::Surface(TextureRuntime& runtime_, const VideoCore::SurfaceParams& params,
|
||||
vk::Format format, vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect)
|
||||
: VideoCore::SurfaceBase{params}, runtime{&runtime_}, instance{&runtime_.GetInstance()},
|
||||
scheduler{&runtime_.GetScheduler()} {
|
||||
if (format != vk::Format::eUndefined) {
|
||||
alloc = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), levels, false, texture_type,
|
||||
format, usage, aspect);
|
||||
alloc = runtime->Allocate(GetScaledWidth(), GetScaledHeight(), levels, false, texture_type,
|
||||
format, usage, aspect);
|
||||
}
|
||||
}
|
||||
|
||||
Surface::~Surface() {
|
||||
if (pixel_format == VideoCore::PixelFormat::Invalid) {
|
||||
if (pixel_format == VideoCore::PixelFormat::Invalid || !alloc.image_view) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -811,11 +803,11 @@ Surface::~Surface() {
|
||||
.levels = alloc.levels,
|
||||
.is_mutable = alloc.is_mutable,
|
||||
};
|
||||
runtime.Recycle(tag, std::move(alloc));
|
||||
runtime->Recycle(tag, std::move(alloc));
|
||||
}
|
||||
|
||||
void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) {
|
||||
runtime.renderpass_cache.ExitRenderpass();
|
||||
runtime->renderpass_cache.ExitRenderpass();
|
||||
|
||||
const bool is_scaled = res_scale != 1;
|
||||
if (is_scaled) {
|
||||
@ -828,8 +820,8 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
|
||||
.src_image = alloc.image,
|
||||
};
|
||||
|
||||
scheduler.Record([buffer = runtime.upload_buffer.Handle(), format = alloc.format, params,
|
||||
staging, upload](vk::CommandBuffer cmdbuf) {
|
||||
scheduler->Record([buffer = runtime->upload_buffer.Handle(), format = alloc.format, params,
|
||||
staging, upload](vk::CommandBuffer cmdbuf) {
|
||||
u32 num_copies = 1;
|
||||
std::array<vk::BufferImageCopy, 2> buffer_image_copies;
|
||||
|
||||
@ -901,12 +893,12 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
|
||||
vk::DependencyFlagBits::eByRegion, {}, {}, write_barrier);
|
||||
});
|
||||
|
||||
runtime.upload_buffer.Commit(staging.size);
|
||||
runtime->upload_buffer.Commit(staging.size);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::Download(const VideoCore::BufferTextureCopy& download, const StagingData& staging) {
|
||||
runtime.renderpass_cache.ExitRenderpass();
|
||||
runtime->renderpass_cache.ExitRenderpass();
|
||||
|
||||
// For depth stencil downloads always use the compute shader fallback
|
||||
// to avoid having the interleave the data later. These should(?) be
|
||||
@ -926,8 +918,8 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
|
||||
.src_image = alloc.image,
|
||||
};
|
||||
|
||||
scheduler.Record([buffer = runtime.download_buffer.Handle(), params, staging,
|
||||
download](vk::CommandBuffer cmdbuf) {
|
||||
scheduler->Record([buffer = runtime->download_buffer.Handle(), params, staging,
|
||||
download](vk::CommandBuffer cmdbuf) {
|
||||
const VideoCore::Rect2D rect = download.texture_rect;
|
||||
const vk::BufferImageCopy buffer_image_copy = {
|
||||
.bufferOffset = staging.buffer_offset + download.buffer_offset,
|
||||
@ -990,12 +982,12 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
|
||||
vk::DependencyFlagBits::eByRegion, memory_write_barrier, {},
|
||||
image_write_barrier);
|
||||
});
|
||||
runtime.download_buffer.Commit(staging.size);
|
||||
runtime->download_buffer.Commit(staging.size);
|
||||
}
|
||||
}
|
||||
|
||||
bool Surface::Swap(u32 width, u32 height, VideoCore::CustomPixelFormat format) {
|
||||
const FormatTraits& traits = instance.GetTraits(format);
|
||||
const FormatTraits& traits = instance->GetTraits(format);
|
||||
if (!traits.transfer_support) {
|
||||
return false;
|
||||
}
|
||||
@ -1013,12 +1005,12 @@ bool Surface::Swap(u32 width, u32 height, VideoCore::CustomPixelFormat format) {
|
||||
.levels = levels,
|
||||
.is_mutable = alloc.is_mutable,
|
||||
};
|
||||
runtime.Recycle(tag, std::move(alloc));
|
||||
runtime->Recycle(tag, std::move(alloc));
|
||||
|
||||
is_custom = true;
|
||||
custom_format = format;
|
||||
alloc = runtime.Allocate(width, height, levels, false, texture_type, custom_vk_format,
|
||||
traits.usage, traits.aspect);
|
||||
alloc = runtime->Allocate(width, height, levels, false, texture_type, custom_vk_format,
|
||||
traits.usage, traits.aspect);
|
||||
|
||||
LOG_DEBUG(Render_Vulkan, "Swapped {}x{} {} surface at address {:#x} to {}x{} {}",
|
||||
GetScaledWidth(), GetScaledHeight(), VideoCore::PixelFormatAsString(pixel_format),
|
||||
@ -1065,15 +1057,15 @@ vk::PipelineStageFlags Surface::PipelineStageFlags() const noexcept {
|
||||
}
|
||||
|
||||
vk::ImageView Surface::DepthView() noexcept {
|
||||
vk::ImageView& depth_view = alloc.depth_view;
|
||||
vk::UniqueImageView& depth_view = alloc.depth_view;
|
||||
if (depth_view) {
|
||||
return depth_view;
|
||||
return depth_view.get();
|
||||
}
|
||||
|
||||
const vk::ImageViewCreateInfo view_info = {
|
||||
.image = alloc.image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = instance.GetTraits(pixel_format).native,
|
||||
.format = instance->GetTraits(pixel_format).native,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eDepth,
|
||||
.baseMipLevel = 0,
|
||||
@ -1083,20 +1075,20 @@ vk::ImageView Surface::DepthView() noexcept {
|
||||
},
|
||||
};
|
||||
|
||||
depth_view = instance.GetDevice().createImageView(view_info);
|
||||
return depth_view;
|
||||
depth_view = instance->GetDevice().createImageViewUnique(view_info);
|
||||
return depth_view.get();
|
||||
}
|
||||
|
||||
vk::ImageView Surface::StencilView() noexcept {
|
||||
vk::ImageView& stencil_view = alloc.stencil_view;
|
||||
vk::UniqueImageView& stencil_view = alloc.stencil_view;
|
||||
if (stencil_view) {
|
||||
return stencil_view;
|
||||
return stencil_view.get();
|
||||
}
|
||||
|
||||
const vk::ImageViewCreateInfo view_info = {
|
||||
.image = alloc.image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = instance.GetTraits(pixel_format).native,
|
||||
.format = instance->GetTraits(pixel_format).native,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eStencil,
|
||||
.baseMipLevel = 0,
|
||||
@ -1106,14 +1098,14 @@ vk::ImageView Surface::StencilView() noexcept {
|
||||
},
|
||||
};
|
||||
|
||||
stencil_view = instance.GetDevice().createImageView(view_info);
|
||||
return stencil_view;
|
||||
stencil_view = instance->GetDevice().createImageViewUnique(view_info);
|
||||
return stencil_view.get();
|
||||
}
|
||||
|
||||
vk::ImageView Surface::StorageView() noexcept {
|
||||
vk::ImageView& storage_view = alloc.storage_view;
|
||||
vk::UniqueImageView& storage_view = alloc.storage_view;
|
||||
if (storage_view) {
|
||||
return storage_view;
|
||||
return storage_view.get();
|
||||
}
|
||||
|
||||
ASSERT_MSG(pixel_format == VideoCore::PixelFormat::RGBA8,
|
||||
@ -1132,8 +1124,8 @@ vk::ImageView Surface::StorageView() noexcept {
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
storage_view = instance.GetDevice().createImageView(storage_view_info);
|
||||
return storage_view;
|
||||
storage_view = instance->GetDevice().createImageViewUnique(storage_view_info);
|
||||
return storage_view.get();
|
||||
}
|
||||
|
||||
void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) {
|
||||
@ -1147,14 +1139,13 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const Sta
|
||||
unscaled_params.stride = rect_width;
|
||||
unscaled_params.height = rect_height;
|
||||
unscaled_params.res_scale = 1;
|
||||
Surface unscaled_surface{unscaled_params, runtime};
|
||||
Surface unscaled_surface{*runtime, unscaled_params};
|
||||
|
||||
const VideoCore::BufferTextureCopy unscaled_upload = {
|
||||
.buffer_offset = upload.buffer_offset,
|
||||
.buffer_size = upload.buffer_size,
|
||||
.texture_rect = unscaled_rect,
|
||||
};
|
||||
|
||||
unscaled_surface.Upload(unscaled_upload, staging);
|
||||
|
||||
const VideoCore::TextureBlit blit = {
|
||||
@ -1165,8 +1156,7 @@ void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const Sta
|
||||
.src_rect = unscaled_rect,
|
||||
.dst_rect = scaled_rect,
|
||||
};
|
||||
|
||||
runtime.BlitTextures(unscaled_surface, *this, blit);
|
||||
runtime->BlitTextures(unscaled_surface, *this, blit);
|
||||
}
|
||||
|
||||
void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
|
||||
@ -1182,7 +1172,7 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
|
||||
unscaled_params.stride = rect_width;
|
||||
unscaled_params.height = rect_height;
|
||||
unscaled_params.res_scale = 1;
|
||||
Surface unscaled_surface{unscaled_params, runtime};
|
||||
Surface unscaled_surface{*runtime, unscaled_params};
|
||||
|
||||
const VideoCore::TextureBlit blit = {
|
||||
.src_level = download.texture_level,
|
||||
@ -1192,9 +1182,7 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
|
||||
.src_rect = scaled_rect,
|
||||
.dst_rect = unscaled_rect,
|
||||
};
|
||||
|
||||
// Blit the scaled rectangle to the unscaled texture
|
||||
runtime.BlitTextures(*this, unscaled_surface, blit);
|
||||
runtime->BlitTextures(*this, unscaled_surface, blit);
|
||||
|
||||
const VideoCore::BufferTextureCopy unscaled_download = {
|
||||
.buffer_offset = download.buffer_offset,
|
||||
@ -1202,7 +1190,6 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
|
||||
.texture_rect = unscaled_rect,
|
||||
.texture_level = 0,
|
||||
};
|
||||
|
||||
unscaled_surface.Download(unscaled_download, staging);
|
||||
}
|
||||
|
||||
@ -1224,10 +1211,10 @@ void Surface::DepthStencilDownload(const VideoCore::BufferTextureCopy& download,
|
||||
r32_params.height = scaled_rect.GetHeight();
|
||||
r32_params.type = VideoCore::SurfaceType::Color;
|
||||
r32_params.res_scale = 1;
|
||||
Surface r32_surface{r32_params, vk::Format::eR32Uint,
|
||||
Surface r32_surface{*runtime, r32_params, vk::Format::eR32Uint,
|
||||
vk::ImageUsageFlagBits::eTransferSrc |
|
||||
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eStorage,
|
||||
vk::ImageAspectFlagBits::eColor, runtime};
|
||||
vk::ImageAspectFlagBits::eColor};
|
||||
|
||||
const VideoCore::TextureBlit blit = {
|
||||
.src_level = download.texture_level,
|
||||
@ -1237,8 +1224,7 @@ void Surface::DepthStencilDownload(const VideoCore::BufferTextureCopy& download,
|
||||
.src_rect = scaled_rect,
|
||||
.dst_rect = r32_scaled_rect,
|
||||
};
|
||||
|
||||
runtime.blit_helper.BlitD24S8ToR32(*this, r32_surface, blit);
|
||||
runtime->blit_helper.BlitD24S8ToR32(*this, r32_surface, blit);
|
||||
|
||||
// Blit the upper mip level to the lower one to scale without additional allocations
|
||||
const bool is_scaled = res_scale != 1;
|
||||
@ -1251,8 +1237,7 @@ void Surface::DepthStencilDownload(const VideoCore::BufferTextureCopy& download,
|
||||
.src_rect = r32_scaled_rect,
|
||||
.dst_rect = unscaled_rect,
|
||||
};
|
||||
|
||||
runtime.BlitTextures(r32_surface, r32_surface, r32_blit);
|
||||
runtime->BlitTextures(r32_surface, r32_surface, r32_blit);
|
||||
}
|
||||
|
||||
const VideoCore::BufferTextureCopy r32_download = {
|
||||
@ -1261,7 +1246,6 @@ void Surface::DepthStencilDownload(const VideoCore::BufferTextureCopy& download,
|
||||
.texture_rect = unscaled_rect,
|
||||
.texture_level = is_scaled ? 1u : 0u,
|
||||
};
|
||||
|
||||
r32_surface.Download(r32_download, staging);
|
||||
}
|
||||
|
||||
@ -1309,8 +1293,7 @@ void Framebuffer::PrepareImages(Surface* const color, Surface* const depth_stenc
|
||||
Prepare(depth_stencil);
|
||||
}
|
||||
|
||||
Sampler::Sampler(TextureRuntime& runtime, VideoCore::SamplerParams params)
|
||||
: device{runtime.GetInstance().GetDevice()} {
|
||||
Sampler::Sampler(TextureRuntime& runtime, const VideoCore::SamplerParams& params) {
|
||||
using TextureConfig = VideoCore::SamplerParams::TextureConfig;
|
||||
|
||||
const Instance& instance = runtime.GetInstance();
|
||||
@ -1352,13 +1335,10 @@ Sampler::Sampler(TextureRuntime& runtime, VideoCore::SamplerParams params)
|
||||
.unnormalizedCoordinates = false,
|
||||
};
|
||||
|
||||
sampler = device.createSampler(sampler_info);
|
||||
vk::Device device = runtime.GetInstance().GetDevice();
|
||||
sampler = device.createSamplerUnique(sampler_info);
|
||||
}
|
||||
|
||||
Sampler::~Sampler() {
|
||||
if (sampler) {
|
||||
device.destroySampler(sampler);
|
||||
}
|
||||
}
|
||||
Sampler::~Sampler() = default;
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@ -25,10 +25,10 @@ namespace Vulkan {
|
||||
|
||||
struct Allocation {
|
||||
vk::Image image;
|
||||
vk::ImageView image_view;
|
||||
vk::ImageView depth_view;
|
||||
vk::ImageView stencil_view;
|
||||
vk::ImageView storage_view;
|
||||
vk::UniqueImageView image_view;
|
||||
vk::UniqueImageView depth_view;
|
||||
vk::UniqueImageView stencil_view;
|
||||
vk::UniqueImageView storage_view;
|
||||
VmaAllocation allocation;
|
||||
vk::ImageAspectFlags aspect;
|
||||
vk::Format format;
|
||||
@ -85,8 +85,8 @@ class TextureRuntime {
|
||||
friend class Sampler;
|
||||
|
||||
public:
|
||||
TextureRuntime(const Instance& instance, Scheduler& scheduler,
|
||||
RenderpassCache& renderpass_cache, DescriptorManager& desc_manager);
|
||||
explicit TextureRuntime(const Instance& instance, Scheduler& scheduler,
|
||||
RenderpassCache& renderpass_cache, DescriptorManager& desc_manager);
|
||||
~TextureRuntime();
|
||||
|
||||
/// Causes a GPU command flush
|
||||
@ -98,7 +98,7 @@ public:
|
||||
/// Takes back ownership of the allocation for recycling
|
||||
void Recycle(const HostTextureTag tag, Allocation&& alloc);
|
||||
|
||||
/// Maps an internal staging buffer of the provided size of pixel uploads/downloads
|
||||
/// Maps an internal staging buffer of the provided size for pixel uploads/downloads
|
||||
[[nodiscard]] VideoCore::StagingData FindStaging(u32 size, bool upload);
|
||||
|
||||
/// Allocates a vulkan image possibly resusing an existing one
|
||||
@ -163,11 +163,17 @@ class Surface : public VideoCore::SurfaceBase {
|
||||
friend class TextureRuntime;
|
||||
|
||||
public:
|
||||
Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime);
|
||||
Surface(const VideoCore::SurfaceParams& params, vk::Format format, vk::ImageUsageFlags usage,
|
||||
vk::ImageAspectFlags aspect, TextureRuntime& runtime);
|
||||
Surface(TextureRuntime& runtime, const VideoCore::SurfaceParams& params);
|
||||
Surface(TextureRuntime& runtime, const VideoCore::SurfaceParams& params, vk::Format format,
|
||||
vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect);
|
||||
~Surface();
|
||||
|
||||
Surface(const Surface&) = delete;
|
||||
Surface& operator=(const Surface&) = delete;
|
||||
|
||||
Surface(Surface&& o) noexcept = default;
|
||||
Surface& operator=(Surface&& o) noexcept = default;
|
||||
|
||||
/// Returns the surface aspect
|
||||
vk::ImageAspectFlags Aspect() const noexcept {
|
||||
return alloc.aspect;
|
||||
@ -180,7 +186,7 @@ public:
|
||||
|
||||
/// Returns an image view used to sample the surface from a shader
|
||||
vk::ImageView ImageView() const noexcept {
|
||||
return alloc.image_view;
|
||||
return alloc.image_view.get();
|
||||
}
|
||||
|
||||
/// Uploads pixel data in staging to a rectangle region of the surface texture
|
||||
@ -218,17 +224,17 @@ private:
|
||||
|
||||
/// Downloads scaled image by downscaling the requested rectangle
|
||||
void ScaledDownload(const VideoCore::BufferTextureCopy& download,
|
||||
const VideoCore::StagingData& stagings);
|
||||
const VideoCore::StagingData& staging);
|
||||
|
||||
/// Downloads scaled depth stencil data
|
||||
void DepthStencilDownload(const VideoCore::BufferTextureCopy& download,
|
||||
const VideoCore::StagingData& staging);
|
||||
|
||||
private:
|
||||
TextureRuntime& runtime;
|
||||
const Instance& instance;
|
||||
Scheduler& scheduler;
|
||||
Allocation alloc;
|
||||
TextureRuntime* runtime;
|
||||
const Instance* instance;
|
||||
Scheduler* scheduler;
|
||||
Allocation alloc{};
|
||||
bool is_framebuffer{};
|
||||
bool is_storage{};
|
||||
};
|
||||
@ -282,34 +288,23 @@ private:
|
||||
u32 height{};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A sampler is used to configure the sampling parameters of a texture unit
|
||||
*/
|
||||
class Sampler {
|
||||
public:
|
||||
Sampler(TextureRuntime& runtime, VideoCore::SamplerParams params);
|
||||
Sampler(TextureRuntime& runtime, const VideoCore::SamplerParams& params);
|
||||
~Sampler();
|
||||
|
||||
Sampler(const Sampler&) = delete;
|
||||
Sampler& operator=(const Sampler&) = delete;
|
||||
|
||||
Sampler(Sampler&& o) noexcept {
|
||||
std::memcpy(this, &o, sizeof(Sampler));
|
||||
o.sampler = VK_NULL_HANDLE;
|
||||
}
|
||||
Sampler& operator=(Sampler&& o) noexcept {
|
||||
std::memcpy(this, &o, sizeof(Sampler));
|
||||
o.sampler = VK_NULL_HANDLE;
|
||||
return *this;
|
||||
}
|
||||
Sampler(Sampler&& o) noexcept = default;
|
||||
Sampler& operator=(Sampler&& o) noexcept = default;
|
||||
|
||||
[[nodiscard]] vk::Sampler Handle() const noexcept {
|
||||
return sampler;
|
||||
return *sampler;
|
||||
}
|
||||
|
||||
private:
|
||||
vk::Device device;
|
||||
vk::Sampler sampler;
|
||||
vk::UniqueSampler sampler;
|
||||
};
|
||||
|
||||
struct Traits {
|
||||
|
Reference in New Issue
Block a user