mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #13446 from hrydgard/assorted-render-fixes
Assorted render fixes
This commit is contained in:
commit
e8d91a2faa
25 changed files with 86 additions and 113 deletions
|
@ -1,4 +1,5 @@
|
|||
#define __STDC_LIMIT_MACROS
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/Vulkan/VulkanLoader.h"
|
||||
#include "Common/Vulkan/VulkanDebug.h"
|
||||
|
||||
|
@ -66,21 +67,21 @@ class VulkanDeleteList {
|
|||
|
||||
public:
|
||||
// NOTE: These all take reference handles so they can zero the input value.
|
||||
void QueueDeleteCommandPool(VkCommandPool &pool) { cmdPools_.push_back(pool); pool = VK_NULL_HANDLE; }
|
||||
void QueueDeleteDescriptorPool(VkDescriptorPool &pool) { descPools_.push_back(pool); pool = VK_NULL_HANDLE; }
|
||||
void QueueDeleteShaderModule(VkShaderModule &module) { modules_.push_back(module); module = VK_NULL_HANDLE; }
|
||||
void QueueDeleteBuffer(VkBuffer &buffer) { buffers_.push_back(buffer); buffer = VK_NULL_HANDLE; }
|
||||
void QueueDeleteBufferView(VkBufferView &bufferView) { bufferViews_.push_back(bufferView); bufferView = VK_NULL_HANDLE; }
|
||||
void QueueDeleteImage(VkImage &image) { images_.push_back(image); image = VK_NULL_HANDLE; }
|
||||
void QueueDeleteImageView(VkImageView &imageView) { imageViews_.push_back(imageView); imageView = VK_NULL_HANDLE; }
|
||||
void QueueDeleteDeviceMemory(VkDeviceMemory &deviceMemory) { deviceMemory_.push_back(deviceMemory); deviceMemory = VK_NULL_HANDLE; }
|
||||
void QueueDeleteSampler(VkSampler &sampler) { samplers_.push_back(sampler); sampler = VK_NULL_HANDLE; }
|
||||
void QueueDeletePipeline(VkPipeline &pipeline) { pipelines_.push_back(pipeline); pipeline = VK_NULL_HANDLE; }
|
||||
void QueueDeletePipelineCache(VkPipelineCache &pipelineCache) { pipelineCaches_.push_back(pipelineCache); pipelineCache = VK_NULL_HANDLE; }
|
||||
void QueueDeleteRenderPass(VkRenderPass &renderPass) { renderPasses_.push_back(renderPass); renderPass = VK_NULL_HANDLE; }
|
||||
void QueueDeleteFramebuffer(VkFramebuffer &framebuffer) { framebuffers_.push_back(framebuffer); framebuffer = VK_NULL_HANDLE; }
|
||||
void QueueDeletePipelineLayout(VkPipelineLayout &pipelineLayout) { pipelineLayouts_.push_back(pipelineLayout); pipelineLayout = VK_NULL_HANDLE; }
|
||||
void QueueDeleteDescriptorSetLayout(VkDescriptorSetLayout &descSetLayout) { descSetLayouts_.push_back(descSetLayout); descSetLayout = VK_NULL_HANDLE; }
|
||||
void QueueDeleteCommandPool(VkCommandPool &pool) { _dbg_assert_(pool != VK_NULL_HANDLE); cmdPools_.push_back(pool); pool = VK_NULL_HANDLE; }
|
||||
void QueueDeleteDescriptorPool(VkDescriptorPool &pool) { _dbg_assert_(pool != VK_NULL_HANDLE); descPools_.push_back(pool); pool = VK_NULL_HANDLE; }
|
||||
void QueueDeleteShaderModule(VkShaderModule &module) { _dbg_assert_(module != VK_NULL_HANDLE); modules_.push_back(module); module = VK_NULL_HANDLE; }
|
||||
void QueueDeleteBuffer(VkBuffer &buffer) { _dbg_assert_(buffer != VK_NULL_HANDLE); buffers_.push_back(buffer); buffer = VK_NULL_HANDLE; }
|
||||
void QueueDeleteBufferView(VkBufferView &bufferView) { _dbg_assert_(bufferView != VK_NULL_HANDLE); bufferViews_.push_back(bufferView); bufferView = VK_NULL_HANDLE; }
|
||||
void QueueDeleteImage(VkImage &image) { _dbg_assert_(image != VK_NULL_HANDLE); images_.push_back(image); image = VK_NULL_HANDLE; }
|
||||
void QueueDeleteImageView(VkImageView &imageView) { _dbg_assert_(imageView != VK_NULL_HANDLE); imageViews_.push_back(imageView); imageView = VK_NULL_HANDLE; }
|
||||
void QueueDeleteDeviceMemory(VkDeviceMemory &deviceMemory) { _dbg_assert_(deviceMemory != VK_NULL_HANDLE); deviceMemory_.push_back(deviceMemory); deviceMemory = VK_NULL_HANDLE; }
|
||||
void QueueDeleteSampler(VkSampler &sampler) { _dbg_assert_(sampler != VK_NULL_HANDLE); samplers_.push_back(sampler); sampler = VK_NULL_HANDLE; }
|
||||
void QueueDeletePipeline(VkPipeline &pipeline) { _dbg_assert_(pipeline != VK_NULL_HANDLE); pipelines_.push_back(pipeline); pipeline = VK_NULL_HANDLE; }
|
||||
void QueueDeletePipelineCache(VkPipelineCache &pipelineCache) { _dbg_assert_(pipelineCache != VK_NULL_HANDLE); pipelineCaches_.push_back(pipelineCache); pipelineCache = VK_NULL_HANDLE; }
|
||||
void QueueDeleteRenderPass(VkRenderPass &renderPass) { _dbg_assert_(renderPass != VK_NULL_HANDLE); renderPasses_.push_back(renderPass); renderPass = VK_NULL_HANDLE; }
|
||||
void QueueDeleteFramebuffer(VkFramebuffer &framebuffer) { _dbg_assert_(framebuffer != VK_NULL_HANDLE); framebuffers_.push_back(framebuffer); framebuffer = VK_NULL_HANDLE; }
|
||||
void QueueDeletePipelineLayout(VkPipelineLayout &pipelineLayout) { _dbg_assert_(pipelineLayout != VK_NULL_HANDLE); pipelineLayouts_.push_back(pipelineLayout); pipelineLayout = VK_NULL_HANDLE; }
|
||||
void QueueDeleteDescriptorSetLayout(VkDescriptorSetLayout &descSetLayout) { _dbg_assert_(descSetLayout != VK_NULL_HANDLE); descSetLayouts_.push_back(descSetLayout); descSetLayout = VK_NULL_HANDLE; }
|
||||
void QueueCallback(void(*func)(void *userdata), void *userdata) { callbacks_.push_back(Callback(func, userdata)); }
|
||||
|
||||
void Take(VulkanDeleteList &del);
|
||||
|
|
|
@ -901,8 +901,8 @@ OpArg FPURegCache::GetDefaultLocation(int reg) const {
|
|||
}
|
||||
|
||||
void FPURegCache::Invariant() const {
|
||||
#ifdef _DEBUG
|
||||
_dbg_assert_msg_(SanityCheck() == 0, "Sanity check failed: %d", SanityCheck());
|
||||
#if 0
|
||||
_assert_msg_(SanityCheck() == 0, "Sanity check failed: %d", SanityCheck());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -347,6 +347,14 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
|||
vfb->fb_stride = params.fb_stride;
|
||||
vfb->z_address = params.z_address;
|
||||
vfb->z_stride = params.z_stride;
|
||||
|
||||
if (vfb->z_address == vfb->fb_address) {
|
||||
// Probably indicates that the game doesn't care about Z for this VFB.
|
||||
// Let's avoid matching it for Z copies.
|
||||
vfb->z_address = 0;
|
||||
vfb->z_stride = 0;
|
||||
}
|
||||
|
||||
vfb->width = drawing_width;
|
||||
vfb->height = drawing_height;
|
||||
vfb->newWidth = drawing_width;
|
||||
|
@ -461,6 +469,26 @@ void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) {
|
|||
delete v;
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) {
|
||||
bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0;
|
||||
bool matchingSize = src->width == dst->width && src->height == dst->height;
|
||||
|
||||
// Note: we don't use CopyFramebufferImage here, because it would copy depth AND stencil. See #9740.
|
||||
if (matchingDepthBuffer && matchingSize) {
|
||||
int w = std::min(src->renderWidth, dst->renderWidth);
|
||||
int h = std::min(src->renderHeight, dst->renderHeight);
|
||||
// Let's only do this if not clearing depth.
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT)) {
|
||||
draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth");
|
||||
RebindFramebuffer("BlitFramebufferDepth");
|
||||
} else if (gstate_c.Supports(GPU_SUPPORTS_COPY_IMAGE)) {
|
||||
draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, w, h, 1, Draw::FB_DEPTH_BIT, "BlitFramebufferDepth");
|
||||
RebindFramebuffer("BlitFramebufferDepth");
|
||||
}
|
||||
dst->last_frame_depth_updated = gpuStats.numFlips;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) {
|
||||
if (!useBufferedRendering_) {
|
||||
// Let's ignore rendering to targets that have not (yet) been displayed.
|
||||
|
|
|
@ -339,7 +339,7 @@ protected:
|
|||
void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth);
|
||||
|
||||
virtual void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) = 0;
|
||||
virtual void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) = 0;
|
||||
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst);
|
||||
|
||||
void ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, int h, bool force = false, bool skipCopy = false);
|
||||
void ShowScreenResolution();
|
||||
|
|
|
@ -315,18 +315,6 @@ static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) {
|
|||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) {
|
||||
bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0;
|
||||
bool matchingSize = src->width == dst->width && src->height == dst->height;
|
||||
bool matchingRenderSize = src->renderWidth == dst->renderWidth && src->renderHeight == dst->renderHeight;
|
||||
if (matchingDepthBuffer && matchingSize && matchingRenderSize) {
|
||||
// TODO: Currently, this copies depth AND stencil, which is a problem. See #9740.
|
||||
draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, src->renderWidth, src->renderHeight, 1, Draw::FB_DEPTH_BIT, "BlitFramebufferDepth");
|
||||
RebindFramebuffer("RebindFramebuffer - BlitFramebufferDepth");
|
||||
dst->last_frame_depth_updated = gpuStats.numFlips;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) {
|
||||
if (!framebuffer->fbo || !useBufferedRendering_) {
|
||||
ID3D11ShaderResourceView *view = nullptr;
|
||||
|
|
|
@ -45,8 +45,6 @@ public:
|
|||
void DeviceLost();
|
||||
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override;
|
||||
|
||||
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override;
|
||||
|
||||
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
|
||||
|
||||
virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
|
||||
|
|
|
@ -146,11 +146,11 @@ void GPU_D3D11::CheckGPUFeatures() {
|
|||
features |= GPU_SUPPORTS_DUALSOURCE_BLEND;
|
||||
if (draw_->GetDeviceCaps().depthClampSupported)
|
||||
features |= GPU_SUPPORTS_DEPTH_CLAMP;
|
||||
features |= GPU_SUPPORTS_ANY_COPY_IMAGE;
|
||||
features |= GPU_SUPPORTS_COPY_IMAGE;
|
||||
features |= GPU_SUPPORTS_TEXTURE_FLOAT;
|
||||
features |= GPU_SUPPORTS_INSTANCE_RENDERING;
|
||||
features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
|
||||
features |= GPU_SUPPORTS_FBO;
|
||||
features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT;
|
||||
|
||||
uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16);
|
||||
uint32_t fmt1555 = draw_->GetDataFormatSupport(Draw::DataFormat::A1R5G5B5_UNORM_PACK16);
|
||||
|
|
|
@ -305,14 +305,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
|
|||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerDX9::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) {
|
||||
bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0;
|
||||
bool matchingSize = src->width == dst->width && src->height == dst->height;
|
||||
if (matchingDepthBuffer && matchingSize) {
|
||||
// Should use StretchRect here? Note: should only copy depth and NOT copy stencil. See #9740.
|
||||
}
|
||||
}
|
||||
|
||||
LPDIRECT3DSURFACE9 FramebufferManagerDX9::GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface, VirtualFramebuffer *vfb) {
|
||||
D3DSURFACE_DESC desc = {};
|
||||
HRESULT hr = similarSurface->GetDesc(&desc);
|
||||
|
|
|
@ -50,8 +50,6 @@ public:
|
|||
void DeviceLost();
|
||||
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override;
|
||||
|
||||
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override;
|
||||
|
||||
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
|
||||
|
||||
virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
|
||||
|
|
|
@ -263,23 +263,6 @@ void FramebufferManagerGLES::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GE
|
|||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) {
|
||||
bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0;
|
||||
bool matchingSize = src->width == dst->width && src->height == dst->height;
|
||||
|
||||
// Note: we don't use CopyFramebufferImage here, because it would copy depth AND stencil. See #9740.
|
||||
if (matchingDepthBuffer && matchingSize) {
|
||||
int w = std::min(src->renderWidth, dst->renderWidth);
|
||||
int h = std::min(src->renderHeight, dst->renderHeight);
|
||||
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT)) {
|
||||
// Let's only do this if not clearing depth.
|
||||
draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth");
|
||||
dst->last_frame_depth_updated = gpuStats.numFlips;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) {
|
||||
if (!framebuffer->fbo || !useBufferedRendering_) {
|
||||
render_->BindTexture(stage, nullptr);
|
||||
|
@ -330,8 +313,7 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX,
|
|||
return;
|
||||
}
|
||||
|
||||
bool useBlit = gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT);
|
||||
bool useNV = useBlit && !gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT);
|
||||
bool useBlit = gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT);
|
||||
|
||||
float srcXFactor = useBlit ? (float)src->renderWidth / (float)src->bufferWidth : 1.0f;
|
||||
float srcYFactor = useBlit ? (float)src->renderHeight / (float)src->bufferHeight : 1.0f;
|
||||
|
@ -361,7 +343,7 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX,
|
|||
return;
|
||||
}
|
||||
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_ANY_COPY_IMAGE)) {
|
||||
if (gstate_c.Supports(GPU_SUPPORTS_COPY_IMAGE)) {
|
||||
// glBlitFramebuffer can clip, but glCopyImageSubData is more restricted.
|
||||
// In case the src goes outside, we just skip the optimization in that case.
|
||||
const bool sameSize = dstX2 - dstX1 == srcX2 - srcX1 && dstY2 - dstY1 == srcY2 - srcY1;
|
||||
|
|
|
@ -49,8 +49,6 @@ public:
|
|||
void DeviceLost();
|
||||
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override;
|
||||
|
||||
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override;
|
||||
|
||||
// For use when texturing from a framebuffer. May create a duplicate if target.
|
||||
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
|
||||
|
||||
|
|
|
@ -182,14 +182,8 @@ void GPU_GLES::CheckGPUFeatures() {
|
|||
}
|
||||
}
|
||||
|
||||
if (gl_extensions.ARB_framebuffer_object || gl_extensions.EXT_framebuffer_object || gl_extensions.IsGLES) {
|
||||
features |= GPU_SUPPORTS_FBO;
|
||||
}
|
||||
if (gl_extensions.ARB_framebuffer_object || gl_extensions.GLES3) {
|
||||
features |= GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT;
|
||||
}
|
||||
if (gl_extensions.NV_framebuffer_blit) {
|
||||
features |= GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT;
|
||||
if (gl_extensions.ARB_framebuffer_object || gl_extensions.NV_framebuffer_blit || gl_extensions.GLES3) {
|
||||
features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT;
|
||||
}
|
||||
if (gl_extensions.ARB_vertex_array_object && gl_extensions.IsCoreContext) {
|
||||
features |= GPU_SUPPORTS_VAO;
|
||||
|
@ -220,7 +214,7 @@ void GPU_GLES::CheckGPUFeatures() {
|
|||
features |= GPU_SUPPORTS_BLEND_MINMAX;
|
||||
|
||||
if (gl_extensions.OES_copy_image || gl_extensions.NV_copy_image || gl_extensions.EXT_copy_image || gl_extensions.ARB_copy_image)
|
||||
features |= GPU_SUPPORTS_ANY_COPY_IMAGE;
|
||||
features |= GPU_SUPPORTS_COPY_IMAGE;
|
||||
|
||||
if (!gl_extensions.IsGLES)
|
||||
features |= GPU_SUPPORTS_LOGIC_OP;
|
||||
|
|
|
@ -158,7 +158,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, StencilUplo
|
|||
|
||||
shaderManagerGL_->DirtyLastShader();
|
||||
|
||||
bool useBlit = gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT);
|
||||
bool useBlit = gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT);
|
||||
|
||||
// Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x.
|
||||
// Then after we're done, we'll just blit it across and stretch it there.
|
||||
|
|
|
@ -124,10 +124,10 @@ void TextureCacheGLES::ApplySamplingParams(const SamplerCacheKey &key) {
|
|||
}
|
||||
|
||||
float aniso = 0.0f;
|
||||
int magKey = ((int)key.mipEnable << 2) | ((int)key.mipFilt << 1) | ((int)key.magFilt);
|
||||
int minKey = ((int)key.mipEnable << 2) | ((int)key.mipFilt << 1) | ((int)key.minFilt);
|
||||
render_->SetTextureSampler(0,
|
||||
key.sClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT, key.tClamp ? GL_CLAMP_TO_EDGE : GL_REPEAT,
|
||||
MagFiltGL[magKey], key.minFilt ? GL_LINEAR : GL_NEAREST, aniso);
|
||||
key.magFilt ? GL_LINEAR : GL_NEAREST, MinFiltGL[minKey], aniso);
|
||||
}
|
||||
|
||||
static void ConvertColors(void *dstBuf, const void *srcBuf, Draw::DataFormat dstFmt, int numPixels) {
|
||||
|
|
|
@ -483,15 +483,13 @@ enum {
|
|||
// Free bit: 16
|
||||
GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17),
|
||||
GPU_SUPPORTS_VAO = FLAG_BIT(18),
|
||||
GPU_SUPPORTS_ANY_COPY_IMAGE = FLAG_BIT(19),
|
||||
GPU_SUPPORTS_COPY_IMAGE = FLAG_BIT(19),
|
||||
GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20),
|
||||
GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21),
|
||||
GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22),
|
||||
GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer
|
||||
GPU_SUPPORTS_TEXTURE_LOD_CONTROL = FLAG_BIT(24),
|
||||
GPU_SUPPORTS_FBO = FLAG_BIT(25),
|
||||
GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT = FLAG_BIT(26),
|
||||
GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT = FLAG_BIT(27),
|
||||
GPU_SUPPORTS_FRAMEBUFFER_BLIT = FLAG_BIT(26),
|
||||
GPU_SUPPORTS_OES_TEXTURE_NPOT = FLAG_BIT(28),
|
||||
GPU_NEEDS_Z_EQUAL_W_HACK = FLAG_BIT(29),
|
||||
GPU_PREFER_CPU_DOWNLOAD = FLAG_BIT(30),
|
||||
|
|
|
@ -388,6 +388,10 @@ VkResult DrawEngineVulkan::RecreateDescriptorPool(FrameData &frame, int newSize)
|
|||
}
|
||||
|
||||
VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone, bool tess) {
|
||||
_dbg_assert_(base != VK_NULL_HANDLE);
|
||||
_dbg_assert_(light != VK_NULL_HANDLE);
|
||||
_dbg_assert_(bone != VK_NULL_HANDLE);
|
||||
|
||||
DescriptorSetKey key;
|
||||
key.imageView_ = imageView;
|
||||
key.sampler_ = sampler;
|
||||
|
@ -396,9 +400,6 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
|
|||
key.base_ = base;
|
||||
key.light_ = light;
|
||||
key.bone_ = bone;
|
||||
_dbg_assert_(base != VK_NULL_HANDLE);
|
||||
_dbg_assert_(light != VK_NULL_HANDLE);
|
||||
_dbg_assert_(bone != VK_NULL_HANDLE);
|
||||
|
||||
FrameData &frame = frame_[vulkan_->GetCurFrame()];
|
||||
// See if we already have this descriptor set cached.
|
||||
|
@ -443,6 +444,8 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
|
|||
int n = 0;
|
||||
VkDescriptorImageInfo tex[3]{};
|
||||
if (imageView) {
|
||||
_dbg_assert_(sampler != VK_NULL_HANDLE);
|
||||
|
||||
#ifdef VULKAN_USE_GENERAL_LAYOUT_FOR_COLOR
|
||||
tex[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
#else
|
||||
|
|
|
@ -269,24 +269,6 @@ void FramebufferManagerVulkan::ReformatFramebufferFrom(VirtualFramebuffer *vfb,
|
|||
}
|
||||
}
|
||||
|
||||
// Except for a missing rebind and silly scissor enables, identical copy of the same function in GPU_GLES - tricky parts are in thin3d.
|
||||
void FramebufferManagerVulkan::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) {
|
||||
bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0;
|
||||
bool matchingSize = src->width == dst->width && src->height == dst->height;
|
||||
bool matchingRenderSize = src->renderWidth == dst->renderWidth && src->renderHeight == dst->renderHeight;
|
||||
if (matchingDepthBuffer && matchingRenderSize && matchingSize) {
|
||||
// TODO: Currently, this copies depth AND stencil, which is a problem. See #9740.
|
||||
draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, src->renderWidth, src->renderHeight, 1, Draw::FB_DEPTH_BIT, "BlitFramebufferDepth");
|
||||
dst->last_frame_depth_updated = gpuStats.numFlips;
|
||||
} else if (matchingDepthBuffer && matchingSize) {
|
||||
/*
|
||||
int w = std::min(src->renderWidth, dst->renderWidth);
|
||||
int h = std::min(src->renderHeight, dst->renderHeight);
|
||||
draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) {
|
||||
if (!framebuffer->fbo || !useBufferedRendering_) {
|
||||
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
|
||||
|
|
|
@ -54,8 +54,6 @@ public:
|
|||
int GetLineWidth();
|
||||
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override;
|
||||
|
||||
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override;
|
||||
|
||||
bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
|
||||
|
||||
VkImageView BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
|
||||
|
|
|
@ -224,9 +224,9 @@ void GPU_Vulkan::CheckGPUFeatures() {
|
|||
|
||||
// Mandatory features on Vulkan, which may be checked in "centralized" code
|
||||
features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
|
||||
features |= GPU_SUPPORTS_FBO;
|
||||
features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT;
|
||||
features |= GPU_SUPPORTS_BLEND_MINMAX;
|
||||
features |= GPU_SUPPORTS_ANY_COPY_IMAGE;
|
||||
features |= GPU_SUPPORTS_COPY_IMAGE;
|
||||
features |= GPU_SUPPORTS_OES_TEXTURE_NPOT;
|
||||
features |= GPU_SUPPORTS_INSTANCE_RENDERING;
|
||||
features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH;
|
||||
|
|
|
@ -34,9 +34,11 @@ std::string GLEnumToString(uint16_t value) {
|
|||
}
|
||||
}
|
||||
|
||||
void CheckGLError(const char *file, int line) {
|
||||
bool CheckGLError(const char *file, int line) {
|
||||
GLenum err = glGetError();
|
||||
if (err != GL_NO_ERROR) {
|
||||
ERROR_LOG(G3D, "GL error %s on %s:%d", GLEnumToString(err).c_str(), file, line);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
#if defined(DEBUG_OPENGL)
|
||||
|
||||
void CheckGLError(const char *file, int line);
|
||||
#define CHECK_GL_ERROR_IF_DEBUG() CheckGLError(__FILE__, __LINE__)
|
||||
bool CheckGLError(const char *file, int line);
|
||||
#define CHECK_GL_ERROR_IF_DEBUG() if (!CheckGLError(__FILE__, __LINE__)) __debugbreak();
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -1146,6 +1146,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
|
|||
if (!tex) {
|
||||
break;
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
if (tex->canWrap) {
|
||||
if (tex->wrapS != c.textureSampler.wrapS) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, c.textureSampler.wrapS);
|
||||
|
@ -1156,14 +1157,17 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
|
|||
tex->wrapT = c.textureSampler.wrapT;
|
||||
}
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
if (tex->magFilter != c.textureSampler.magFilter) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, c.textureSampler.magFilter);
|
||||
tex->magFilter = c.textureSampler.magFilter;
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
if (tex->minFilter != c.textureSampler.minFilter) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, c.textureSampler.minFilter);
|
||||
tex->minFilter = c.textureSampler.minFilter;
|
||||
}
|
||||
CHECK_GL_ERROR_IF_DEBUG();
|
||||
if (tex->anisotropy != c.textureSampler.anisotropy) {
|
||||
if (c.textureSampler.anisotropy != 0.0f) {
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, c.textureSampler.anisotropy);
|
||||
|
|
|
@ -89,8 +89,12 @@ void VulkanQueueRunner::ResizeReadbackBuffer(VkDeviceSize requiredSize) {
|
|||
|
||||
void VulkanQueueRunner::DestroyDeviceObjects() {
|
||||
INFO_LOG(G3D, "VulkanQueueRunner::DestroyDeviceObjects");
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(readbackMemory_);
|
||||
vulkan_->Delete().QueueDeleteBuffer(readbackBuffer_);
|
||||
if (readbackMemory_) {
|
||||
vulkan_->Delete().QueueDeleteDeviceMemory(readbackMemory_);
|
||||
}
|
||||
if (readbackBuffer_) {
|
||||
vulkan_->Delete().QueueDeleteBuffer(readbackBuffer_);
|
||||
}
|
||||
readbackBufferSize_ = 0;
|
||||
|
||||
renderPasses_.Iterate([&](const RPKey &rpkey, VkRenderPass rp) {
|
||||
|
|
|
@ -526,7 +526,9 @@ public:
|
|||
|
||||
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
|
||||
|
||||
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override {}
|
||||
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override {
|
||||
// Not implemented
|
||||
}
|
||||
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override;
|
||||
|
||||
// These functions should be self explanatory.
|
||||
|
|
Loading…
Add table
Reference in a new issue