Merge branch 'master' into compat_openxr_fixes

This commit is contained in:
Lubos 2022-12-01 18:26:26 +01:00
commit 2be8f46a0c
14 changed files with 254 additions and 170 deletions

View File

@ -69,6 +69,7 @@ jobs:
path: ppsspp/
build-uwp:
if: ${{false}} # Temporarily disable
runs-on: windows-latest
steps:
- uses: actions/checkout@v3

View File

@ -1136,11 +1136,21 @@ bool VulkanContext::InitSwapchain() {
INFO_LOG(G3D, "Transform supported: %s current: %s chosen: %s", supportedTransforms.c_str(), currentTransform.c_str(), preTransformStr.c_str());
if (physicalDeviceProperties_[physical_device_].properties.vendorID == VULKAN_VENDOR_IMGTEC) {
INFO_LOG(G3D, "Applying PowerVR hack (rounding off the width!)");
// Swap chain width hack to avoid issue #11743 (PowerVR driver bug).
// To keep the size consistent even with pretransform, do this after the swap. Should be fine.
// This is fixed in newer PowerVR drivers but I don't know the cutoff.
swapChainExtent_.width &= ~31;
u32 driverVersion = physicalDeviceProperties_[physical_device_].properties.driverVersion;
// Cutoff the hack at driver version 1.386.1368 (0x00582558, see issue #15773).
if (driverVersion < 0x00582558) {
INFO_LOG(G3D, "Applying PowerVR hack (rounding off the width!) driverVersion=%08x", driverVersion);
// Swap chain width hack to avoid issue #11743 (PowerVR driver bug).
// To keep the size consistent even with pretransform, do this after the swap. Should be fine.
// This is fixed in newer PowerVR drivers but I don't know the cutoff.
swapChainExtent_.width &= ~31;
// TODO: Also modify display_xres/display_yres appropriately for scissors to match.
// This will get a bit messy. Ideally we should remove that logic from app-android.cpp
// and move it here, but the OpenGL code still needs it.
} else {
INFO_LOG(G3D, "PowerVR driver version new enough (%08x), not applying swapchain width hack", driverVersion);
}
}
VkSwapchainCreateInfoKHR swap_chain_info{ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };

View File

@ -172,7 +172,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
bool fetchFramebuffer = needFramebufferRead && id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH);
bool readFramebufferTex = needFramebufferRead && !id.Bit(FS_BIT_USE_FRAMEBUFFER_FETCH);
if (fetchFramebuffer && (compat.shaderLanguage != GLSL_VULKAN || compat.shaderLanguage != GLSL_3xx)) {
if (fetchFramebuffer && compat.shaderLanguage != GLSL_VULKAN && (compat.shaderLanguage != GLSL_3xx || !compat.lastFragData)) {
*errorString = "framebuffer fetch requires GLSL: vulkan or 3xx";
return false;
}
@ -568,7 +568,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
if (compat.shaderLanguage == GLSL_3xx) {
WRITE(p, " lowp vec4 destColor = %s;\n", compat.lastFragData);
} else if (compat.shaderLanguage == GLSL_VULKAN) {
WRITE(p, " lowp vec4 destColor = subpassLoad(inputColor);\n", compat.lastFragData);
WRITE(p, " lowp vec4 destColor = subpassLoad(inputColor);\n");
} else {
_assert_msg_(false, "Need fetch destColor, but not a compatible language");
}

View File

@ -3057,72 +3057,188 @@ void GPUCommon::DoBlockTransfer(u32 skipDrawReason) {
DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY);
if (!Memory::IsValidAddress(srcBasePtr)) {
ERROR_LOG_REPORT(G3D, "BlockTransfer: Bad source transfer address %08x!", srcBasePtr);
return;
}
// For VRAM, we wrap around when outside valid memory (mirrors still work.)
if ((srcBasePtr & 0x04800000) == 0x04800000)
srcBasePtr &= ~0x00800000;
if ((dstBasePtr & 0x04800000) == 0x04800000)
dstBasePtr &= ~0x00800000;
if (!Memory::IsValidAddress(dstBasePtr)) {
ERROR_LOG_REPORT(G3D, "BlockTransfer: Bad destination transfer address %08x!", dstBasePtr);
return;
}
// Use height less one to account for width, which can be greater or less than stride.
const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp;
const uint32_t srcSize = (height - 1) * (srcStride + width) * bpp;
const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp;
const uint32_t dstSize = (height - 1) * (dstStride + width) * bpp;
// Check that the last address of both source and dest are valid addresses
u32 srcLastAddr = srcBasePtr + ((srcY + height - 1) * srcStride + (srcX + width - 1)) * bpp;
u32 dstLastAddr = dstBasePtr + ((dstY + height - 1) * dstStride + (dstX + width - 1)) * bpp;
if (!Memory::IsValidAddress(srcLastAddr)) {
ERROR_LOG_N_TIMES(bad_xfer_src, 5, G3D, "Bottom-right corner of source of %dx%d src=(%d, %d) block transfer from buffer at %08x is at an invalid address: %08x. Skipping.", width, height, srcX, srcY, srcBasePtr, srcLastAddr);
return;
}
if (!Memory::IsValidAddress(dstLastAddr)) {
ERROR_LOG_N_TIMES(bad_xfer_src, 5, G3D, "Bottom-right corner of destination of %dx%d dst=(%d, %d) block transfer to buffer at %08x is at an invalid address: %08x. Skipping.", width, height, dstX, dstY, dstBasePtr, srcLastAddr);
return;
}
bool srcDstOverlap = src + srcSize > dst && dst + dstSize > src;
bool srcValid = Memory::IsValidRange(src, srcSize);
bool dstValid = Memory::IsValidRange(dst, dstSize);
bool srcWraps = Memory::IsVRAMAddress(srcBasePtr) && !srcValid;
bool dstWraps = Memory::IsVRAMAddress(dstBasePtr) && !dstValid;
// Tell the framebuffer manager to take action if possible. If it does the entire thing, let's just return.
if (!framebufferManager_->NotifyBlockTransferBefore(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason)) {
if (!framebufferManager_ || !framebufferManager_->NotifyBlockTransferBefore(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason)) {
// Do the copy! (Hm, if we detect a drawn video frame (see below) then we could maybe skip this?)
// Can use GetPointerUnchecked because we checked the addresses above. We could also avoid them
// entirely by walking a couple of pointers...
if (srcStride == dstStride && (u32)width == srcStride) {
// Common case in God of War, let's do it all in one chunk.
// Simple case: just a straight copy, no overlap or wrapping.
if (srcStride == dstStride && (u32)width == srcStride && !srcDstOverlap && srcValid && dstValid) {
u32 srcLineStartAddr = srcBasePtr + (srcY * srcStride + srcX) * bpp;
u32 dstLineStartAddr = dstBasePtr + (dstY * dstStride + dstX) * bpp;
const u8 *src = Memory::GetPointerUnchecked(srcLineStartAddr);
u8 *dst = Memory::GetPointerWriteUnchecked(dstLineStartAddr);
memcpy(dst, src, width * height * bpp);
GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * height * bpp);
} else {
u32 bytesToCopy = width * height * bpp;
const u8 *srcp = Memory::GetPointer(srcLineStartAddr);
u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr);
memcpy(dstp, srcp, bytesToCopy);
if (MemBlockInfoDetailed(bytesToCopy)) {
const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, bytesToCopy);
NotifyMemInfo(MemBlockFlags::READ, src, bytesToCopy, tag.c_str(), tag.size());
NotifyMemInfo(MemBlockFlags::WRITE, dst, bytesToCopy, tag.c_str(), tag.size());
}
} else if ((srcDstOverlap || srcWraps || dstWraps) && (srcValid || srcWraps) && (dstValid || dstWraps)) {
// This path means we have either src/dst overlap, OR one or both of src and dst wrap.
// This should be uncommon so it's the slowest path.
u32 bytesToCopy = width * bpp;
static std::string tag;
bool notifyDetail = MemBlockInfoDetailed(srcWraps || dstWraps ? 64 : bytesToCopy);
bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize);
if (notifyDetail || notifyAll) {
tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize);
}
auto notifyingMemmove = [&](u32 d, u32 s, u32 sz) {
const u8 *srcp = Memory::GetPointer(s);
u8 *dstp = Memory::GetPointerWrite(d);
memmove(dstp, srcp, sz);
if (notifyDetail) {
NotifyMemInfo(MemBlockFlags::READ, s, sz, tag.c_str(), tag.size());
NotifyMemInfo(MemBlockFlags::WRITE, d, sz, tag.c_str(), tag.size());
}
};
for (int y = 0; y < height; y++) {
u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp;
u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp;
// If we already passed a wrap, we can use the quicker path.
if ((srcLineStartAddr & 0x04800000) == 0x04800000)
srcLineStartAddr &= ~0x00800000;
if ((dstLineStartAddr & 0x04800000) == 0x04800000)
dstLineStartAddr &= ~0x00800000;
// These flags mean there's a wrap inside this line.
bool srcLineWrap = !Memory::IsValidRange(srcLineStartAddr, bytesToCopy);
bool dstLineWrap = !Memory::IsValidRange(dstLineStartAddr, bytesToCopy);
if (!srcLineWrap && !dstLineWrap) {
const u8 *srcp = Memory::GetPointer(srcLineStartAddr);
u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr);
for (u32 i = 0; i < bytesToCopy; i += 64) {
u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64;
memmove(dstp + i, srcp + i, chunk);
}
// If we're tracking detail, it's useful to have the gaps illustrated properly.
if (notifyDetail) {
NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size());
NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size());
}
} else {
// We can wrap at any point, so along with overlap this gets a bit complicated.
// We're just going to do this the slow and easy way.
u32 srcLinePos = srcLineStartAddr;
u32 dstLinePos = dstLineStartAddr;
for (u32 i = 0; i < bytesToCopy; i += 64) {
u32 chunk = i + 64 > bytesToCopy ? bytesToCopy - i : 64;
u32 srcValid = Memory::ValidSize(srcLinePos, chunk);
u32 dstValid = Memory::ValidSize(dstLinePos, chunk);
// First chunk, for which both are valid.
u32 bothSize = std::min(srcValid, dstValid);
if (bothSize != 0)
notifyingMemmove(dstLinePos, srcLinePos, bothSize);
// Now, whichever side has more valid (or the rest, if only one side must wrap.)
u32 exclusiveSize = std::max(srcValid, dstValid) - bothSize;
if (exclusiveSize != 0 && srcValid >= dstValid) {
notifyingMemmove(PSP_GetVidMemBase(), srcLineStartAddr + bothSize, exclusiveSize);
} else if (exclusiveSize != 0 && srcValid < dstValid) {
notifyingMemmove(dstLineStartAddr + bothSize, PSP_GetVidMemBase(), exclusiveSize);
}
// Finally, if both src and dst wrapped, that portion.
u32 wrappedSize = chunk - bothSize - exclusiveSize;
if (wrappedSize != 0 && srcValid >= dstValid) {
notifyingMemmove(PSP_GetVidMemBase() + exclusiveSize, PSP_GetVidMemBase(), wrappedSize);
} else if (wrappedSize != 0 && srcValid < dstValid) {
notifyingMemmove(PSP_GetVidMemBase(), PSP_GetVidMemBase() + exclusiveSize, wrappedSize);
}
srcLinePos += chunk;
dstLinePos += chunk;
if ((srcLinePos & 0x04800000) == 0x04800000)
srcLinePos &= ~0x00800000;
if ((dstLinePos & 0x04800000) == 0x04800000)
dstLinePos &= ~0x00800000;
}
}
}
if (notifyAll) {
if (srcWraps) {
u32 validSize = Memory::ValidSize(src, srcSize);
NotifyMemInfo(MemBlockFlags::READ, src, validSize, tag.c_str(), tag.size());
NotifyMemInfo(MemBlockFlags::READ, PSP_GetVidMemBase(), srcSize - validSize, tag.c_str(), tag.size());
} else {
NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size());
}
if (dstWraps) {
u32 validSize = Memory::ValidSize(dst, dstSize);
NotifyMemInfo(MemBlockFlags::WRITE, dst, validSize, tag.c_str(), tag.size());
NotifyMemInfo(MemBlockFlags::WRITE, PSP_GetVidMemBase(), dstSize - validSize, tag.c_str(), tag.size());
} else {
NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size());
}
}
} else if (srcValid && dstValid) {
u32 bytesToCopy = width * bpp;
static std::string tag;
bool notifyDetail = MemBlockInfoDetailed(bytesToCopy);
bool notifyAll = !notifyDetail && MemBlockInfoDetailed(srcSize, dstSize);
if (notifyDetail || notifyAll) {
tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize);
}
for (int y = 0; y < height; y++) {
u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp;
u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp;
const u8 *src = Memory::GetPointerUnchecked(srcLineStartAddr);
u8 *dst = Memory::GetPointerWriteUnchecked(dstLineStartAddr);
memcpy(dst, src, width * bpp);
GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * bpp);
const u8 *srcp = Memory::GetPointer(srcLineStartAddr);
u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr);
memcpy(dstp, srcp, bytesToCopy);
// If we're tracking detail, it's useful to have the gaps illustrated properly.
if (notifyDetail) {
NotifyMemInfo(MemBlockFlags::READ, srcLineStartAddr, bytesToCopy, tag.c_str(), tag.size());
NotifyMemInfo(MemBlockFlags::WRITE, dstLineStartAddr, bytesToCopy, tag.c_str(), tag.size());
}
}
if (notifyAll) {
NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size());
NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size());
}
} else {
// This seems to cause the GE to require a break/reset on a PSP.
// TODO: Handle that and figure out which bytes are still copied?
ERROR_LOG_REPORT_ONCE(invalidtransfer, G3D, "Block transfer invalid: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY);
}
// Fixes Gran Turismo's funky text issue, since it overwrites the current texture.
textureCache_->Invalidate(dstBasePtr + (dstY * dstStride + dstX) * bpp, height * dstStride * bpp, GPU_INVALIDATE_HINT);
framebufferManager_->NotifyBlockTransferAfter(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason);
}
const uint32_t numBytes = width * height * bpp;
const uint32_t srcSize = height * srcStride * bpp;
const uint32_t dstSize = height * dstStride * bpp;
// We do the check here on the number of bytes to avoid marking really tiny images.
// Helps perf in GT menu which does insane amounts of these, one for each text character per frame.
if (MemBlockInfoDetailed(numBytes, numBytes)) {
const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp;
const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp;
char tag[128];
size_t tagSize = FormatMemWriteTagAt(tag, sizeof(tag), "GPUBlockTransfer/", src, srcSize);
NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag, tagSize);
NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag, tagSize);
if (framebufferManager_) {
// Fixes Gran Turismo's funky text issue, since it overwrites the current texture.
textureCache_->Invalidate(dstBasePtr + (dstY * dstStride + dstX) * bpp, height * dstStride * bpp, GPU_INVALIDATE_HINT);
framebufferManager_->NotifyBlockTransferAfter(dstBasePtr, dstStride, dstX, dstY, srcBasePtr, srcStride, srcX, srcY, width, height, bpp, skipDrawReason);
}
}
// TODO: Correct timing appears to be 1.9, but erring a bit low since some of our other timing is inaccurate.

View File

@ -301,6 +301,7 @@ protected:
void UpdateState(GPURunState state);
void FastLoadBoneMatrix(u32 target);
void FlushImm();
void DoBlockTransfer(u32 skipDrawReason);
// TODO: Unify this.
virtual void FinishDeferred() {}
@ -406,7 +407,6 @@ protected:
private:
void CheckDepthUsage(VirtualFramebuffer *vfb);
void DoBlockTransfer(u32 skipDrawReason);
void DoExecuteCall(u32 target);
void PopDLQueue();
void CheckDrawSync();

View File

@ -50,16 +50,15 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C,
}
inline void clip_interpolate(ClipVertexData &dest, float t, const ClipVertexData &a, const ClipVertexData &b) {
if (different_signs(a.clippos.w, b.clippos.w)) {
if (a.clippos.w < -1.0f || b.clippos.w < -1.0f) {
dest.v.screenpos.x = 0x7FFFFFFF;
return;
}
}
bool outsideRange = false;
dest.Lerp(t, a, b);
dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos);
dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos, &outsideRange);
dest.v.clipw = dest.clippos.w;
// If the clipped coordinate is outside range, then we throw it away.
// This prevents a lot of inversions that shouldn't be drawn.
if (outsideRange)
dest.v.screenpos.x = 0x7FFFFFFF;
}
#define CLIP_POLY( PLANE_BIT, A, B, C, D ) \

View File

@ -29,6 +29,7 @@
#include "Core/Core.h"
#include "Core/Debugger/MemBlockInfo.h"
#include "Core/MemMap.h"
#include "Core/MemMapHelpers.h"
#include "Core/HLE/sceKernelInterrupt.h"
#include "Core/HLE/sceGe.h"
#include "Core/MIPS/MIPS.h"
@ -792,68 +793,21 @@ void SoftGPU::Execute_BlockTransferStart(u32 op, u32 diff) {
int bpp = gstate.getTransferBpp();
// Use height less one to account for width, which can be greater or less than stride.
const uint32_t src = srcBasePtr + (srcY * srcStride + srcX) * bpp;
const uint32_t srcSize = height * srcStride * bpp;
const uint32_t srcSize = (height - 1) * (srcStride + width) * bpp;
const uint32_t dst = dstBasePtr + (dstY * dstStride + dstX) * bpp;
const uint32_t dstSize = height * dstStride * bpp;
const uint32_t dstSize = (height - 1) * (dstStride + width) * bpp;
// Need to flush both source and target, so we overwrite properly.
drawEngine_->transformUnit.FlushIfOverlap("blockxfer", false, src, srcStride, width * bpp, height);
drawEngine_->transformUnit.FlushIfOverlap("blockxfer", true, dst, dstStride, width * bpp, height);
DEBUG_LOG(G3D, "Block transfer: %08x/%x -> %08x/%x, %ix%ix%i (%i,%i)->(%i,%i)", srcBasePtr, srcStride, dstBasePtr, dstStride, width, height, bpp, srcX, srcY, dstX, dstY);
if (srcStride == dstStride && (u32)width == srcStride) {
u32 srcLineStartAddr = srcBasePtr + (srcY * srcStride + srcX) * bpp;
u32 dstLineStartAddr = dstBasePtr + (dstY * dstStride + dstX) * bpp;
u32 bytesToCopy = width * height * bpp;
if (!Memory::IsValidRange(srcLineStartAddr, bytesToCopy)) {
// What should we do here? Memset zeroes to the dest instead?
return;
}
if (!Memory::IsValidRange(dstLineStartAddr, bytesToCopy)) {
// What should we do here? Just not do the write, or partial write if
// some part is in-range?
return;
}
const u8 *srcp = Memory::GetPointer(srcLineStartAddr);
u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr);
memcpy(dstp, srcp, bytesToCopy);
GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, bytesToCopy);
if (Memory::IsValidRange(src, srcSize) && Memory::IsValidRange(dst, dstSize)) {
drawEngine_->transformUnit.FlushIfOverlap("blockxfer", false, src, srcStride, width * bpp, height);
drawEngine_->transformUnit.FlushIfOverlap("blockxfer", true, dst, dstStride, width * bpp, height);
} else {
for (int y = 0; y < height; y++) {
u32 srcLineStartAddr = srcBasePtr + ((y + srcY) * srcStride + srcX) * bpp;
u32 dstLineStartAddr = dstBasePtr + ((y + dstY) * dstStride + dstX) * bpp;
u32 bytesToCopy = width * bpp;
if (!Memory::IsValidRange(srcLineStartAddr, bytesToCopy)) {
// What should we do here? Due to the y loop, in this case we might have
// performed a partial copy. Probably fine.
break;
}
if (!Memory::IsValidRange(dstLineStartAddr, bytesToCopy)) {
// What should we do here? Due to the y loop, in this case we might have
// performed a partial copy. Probably fine.
break;
}
const u8 *srcp = Memory::GetPointer(srcLineStartAddr);
u8 *dstp = Memory::GetPointerWrite(dstLineStartAddr);
memcpy(dstp, srcp, width * bpp);
GPURecord::NotifyMemcpy(dstLineStartAddr, srcLineStartAddr, width * bpp);
}
drawEngine_->transformUnit.Flush("blockxfer_wrap");
}
if (MemBlockInfoDetailed(srcSize, dstSize)) {
const std::string tag = GetMemWriteTagAt("GPUBlockTransfer/", src, srcSize);
NotifyMemInfo(MemBlockFlags::READ, src, srcSize, tag.c_str(), tag.size());
NotifyMemInfo(MemBlockFlags::WRITE, dst, dstSize, tag.c_str(), tag.size());
}
// TODO: Correct timing appears to be 1.9, but erring a bit low since some of our other timing is inaccurate.
cyclesExecuted += ((height * width * bpp) * 16) / 10;
DoBlockTransfer(gstate_c.skipDrawReason);
// Could theoretically dirty the framebuffer.
MarkDirty(dst, dstSize, SoftGPUVRAMDirty::DIRTY | SoftGPUVRAMDirty::REALLY_DIRTY);

View File

@ -162,7 +162,7 @@ ClipCoords TransformUnit::ViewToClip(const ViewCoords &coords) {
return Vec3ByMatrix44(coords, gstate.projMatrix);
}
template <bool depthClamp, bool writeOutsideFlag>
template <bool depthClamp, bool alwaysCheckRange>
static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, bool *outside_range_flag) {
ScreenCoords ret;
@ -173,7 +173,7 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords,
// This matches hardware tests - depth is clamped when this flag is on.
if (depthClamp) {
// Note: if the depth is clipped (z/w <= -1.0), the outside_range_flag should NOT be set, even for x and y.
if (writeOutsideFlag && coords.z > -coords.w && (scaled.x >= SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) {
if ((alwaysCheckRange || coords.z > -coords.w) && (scaled.x >= SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) {
*outside_range_flag = true;
}
@ -181,7 +181,7 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords,
scaled.z = 0.f;
else if (scaled.z > 65535.0f)
scaled.z = 65535.0f;
} else if (writeOutsideFlag && (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) {
} else if (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0) {
*outside_range_flag = true;
}
@ -209,17 +209,13 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords &coords, bool *
float z = coords.z * zScale / coords.w + zCenter;
if (gstate.isDepthClampEnabled()) {
if (outside_range_flag)
return ClipToScreenInternal<true, true>(Vec3f(x, y, z), coords, outside_range_flag);
return ClipToScreenInternal<true, false>(Vec3f(x, y, z), coords, outside_range_flag);
return ClipToScreenInternal<true, true>(Vec3f(x, y, z), coords, outside_range_flag);
}
if (outside_range_flag)
return ClipToScreenInternal<false, true>(Vec3f(x, y, z), coords, outside_range_flag);
return ClipToScreenInternal<false, false>(Vec3f(x, y, z), coords, outside_range_flag);
return ClipToScreenInternal<false, true>(Vec3f(x, y, z), coords, outside_range_flag);
}
ScreenCoords TransformUnit::ClipToScreen(const ClipCoords &coords) {
return ClipToScreenInternal(coords, nullptr);
ScreenCoords TransformUnit::ClipToScreen(const ClipCoords &coords, bool *outsideRangeFlag) {
return ClipToScreenInternal(coords, outsideRangeFlag);
}
ScreenCoords TransformUnit::DrawingToScreen(const DrawingCoords &coords, u16 z) {
@ -317,9 +313,9 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) {
}
if (gstate.isDepthClampEnabled())
state->roundToScreen = &ClipToScreenInternal<true, true>;
state->roundToScreen = &ClipToScreenInternal<true, false>;
else
state->roundToScreen = &ClipToScreenInternal<false, true>;
state->roundToScreen = &ClipToScreenInternal<false, false>;
}
ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformState &state) {
@ -977,7 +973,8 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVert
vertices[i].z = vert.pos.z;
} else {
Vec4f clipPos = Vec3ByMatrix44(vert.pos, worldviewproj);
ScreenCoords screenPos = ClipToScreen(clipPos);
bool outsideRangeFlag;
ScreenCoords screenPos = ClipToScreen(clipPos, &outsideRangeFlag);
float z = clipPos.z * zScale / clipPos.w + zCenter;
if (gstate.vertType & GE_VTYPE_TC_MASK) {

View File

@ -121,7 +121,7 @@ public:
static WorldCoords ModelToWorld(const ModelCoords& coords);
static ViewCoords WorldToView(const WorldCoords& coords);
static ClipCoords ViewToClip(const ViewCoords& coords);
static ScreenCoords ClipToScreen(const ClipCoords& coords);
static ScreenCoords ClipToScreen(const ClipCoords &coords, bool *outsideRangeFlag);
static inline DrawingCoords ScreenToDrawing(int x, int y) {
DrawingCoords ret;
// When offset > coord, this is negative and force-scissors.

View File

@ -63,15 +63,14 @@ public:
bool Touch(const TouchInput &touch) {
int mode = mode_ ? mode_->GetSelection() : 0;
const Bounds &screenBounds = bounds_;
if ((touch.flags & TOUCH_MOVE) != 0 && dragging_) {
float relativeTouchX = touch.x - startX_;
float relativeTouchY = touch.y - startY_;
switch (mode) {
case MODE_MOVE:
g_Config.fDisplayOffsetX = clamp_value(startDisplayOffsetX_ + relativeTouchX / screenBounds.w, 0.0f, 1.0f);
g_Config.fDisplayOffsetY = clamp_value(startDisplayOffsetY_ + relativeTouchY / screenBounds.h, 0.0f, 1.0f);
g_Config.fDisplayOffsetX = clamp_value(startDisplayOffsetX_ + relativeTouchX / bounds_.w, 0.0f, 1.0f);
g_Config.fDisplayOffsetY = clamp_value(startDisplayOffsetY_ + relativeTouchY / bounds_.h, 0.0f, 1.0f);
break;
case MODE_RESIZE:
{
@ -84,12 +83,18 @@ public:
}
if ((touch.flags & TOUCH_DOWN) != 0 && !dragging_) {
dragging_ = true;
startX_ = touch.x;
startY_ = touch.y;
startDisplayOffsetX_ = g_Config.fDisplayOffsetX;
startDisplayOffsetY_ = g_Config.fDisplayOffsetY;
startScale_ = g_Config.fDisplayScale;
// Check that we're in the central 80% of the screen.
// If outside, it may be a drag from displaying the back button on phones
// where you have to drag from the side, etc.
if (touch.x >= bounds_.w * 0.1f && touch.x <= bounds_.w * 0.9f &&
touch.y >= bounds_.h * 0.1f && touch.y <= bounds_.h * 0.9f) {
dragging_ = true;
startX_ = touch.x;
startY_ = touch.y;
startDisplayOffsetX_ = g_Config.fDisplayOffsetX;
startDisplayOffsetY_ = g_Config.fDisplayOffsetY;
startScale_ = g_Config.fDisplayScale;
}
}
if ((touch.flags & TOUCH_UP) != 0 && dragging_) {
@ -208,7 +213,7 @@ void DisplayLayoutScreen::CreateViews() {
auto stretch = new CheckBox(&g_Config.bDisplayStretch, gr->T("Stretch"));
leftColumn->Add(stretch);
PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, di->T("Aspect Ratio"), screenManager());
PopupSliderChoiceFloat *aspectRatio = new PopupSliderChoiceFloat(&g_Config.fDisplayAspectRatio, 0.5f, 2.0f, gr->T("Aspect Ratio"), screenManager());
leftColumn->Add(aspectRatio);
aspectRatio->SetDisabledPtr(&g_Config.bDisplayStretch);
aspectRatio->SetHasDropShadow(false);

View File

@ -1793,7 +1793,7 @@ void DeveloperToolsScreen::CreateViews() {
list->Add(new CheckBox(&g_Config.bStereoRendering, gr->T("Stereo rendering")));
std::vector<std::string> stereoShaderNames;
ChoiceWithValueDisplay *stereoShaderChoice = list->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, "Stereo display shader", &PostShaderTranslateName));
ChoiceWithValueDisplay *stereoShaderChoice = list->Add(new ChoiceWithValueDisplay(&g_Config.sStereoToMonoShader, gr->T("Stereo display shader"), &PostShaderTranslateName));
stereoShaderChoice->SetEnabledFunc(enableStereo);
stereoShaderChoice->OnClick.Add([=](EventParams &e) {
auto gr = GetI18NCategory("Graphics");

View File

@ -82,7 +82,7 @@ Portrait = Портретная
Portrait Reversed = Портретная (перевернутая)
PSP Action Buttons = Кнопки действий PSP
Raw input = Прямой ввод
Repeat mode = Repeat mode
Repeat mode = Режим повтора
Reset to defaults = По умолчанию
Screen aligned to ground = Экран повёрнут к земле
Screen at right angle to ground = Экран повёрнут под прямым углом к земле
@ -240,7 +240,7 @@ FPU = FPU
Framedump tests = Тест дампов кадров
Frame Profiler = Профайлер кадров
GPU Driver Test = Проверка драйвера ГП
GPU log profiler = GPU log profiler
GPU log profiler = Профилировщик логов ГП
GPU Profile = Профиль ГП
Jit Compare = Сравнение с JIT
JIT debug tools = Инструменты отладки JIT
@ -456,7 +456,7 @@ Aggressive = Принудительно
Alternative Speed = Другая скорость (в %, 0 = без ограничений)
Alternative Speed 2 = Другая скорость 2 (в %, 0 = без ограничений)
Anisotropic Filtering = Анизотропная фильтрация
Aspect Ratio = Aspect Ratio
Aspect Ratio = Соотношение сторон
Auto = Авто
Auto (1:1) = Авто (1:1)
Auto (same as Rendering) = Авто (как разрешение рендеринга)
@ -488,14 +488,13 @@ Disabled = Отключено
Display Layout && Effects = Редактор расположения экрана
Display Resolution (HW scaler) = Разрешение экрана (аппаратное)
Enable Cardboard VR = Включить Cardboard VR
#Features = Возможности
FPS = FPS
Frame Rate Control = Управление частотой кадров
Frame Skipping = Пропуск кадров
Frame Skipping Type = Тип пропуска кадров
FullScreen = Полноэкранный режим
Geometry shader culling = Geometry shader culling
GPUReadbackRequired = Warning: This game requires "Skip GPU Readbacks" to be set to Off.
Geometry shader culling = Вызов геометрических шейдеров
GPUReadbackRequired = Внимание: Для данной игры нужно отключить настройку "Пропускать чтение данных ГП".
Hack Settings = Параметры хаков (могут вызывать глюки)
Hardware Tessellation = Аппаратная тесселяция
Hardware Transform = Аппаратное преобразование
@ -542,20 +541,20 @@ Safe = Безопасно
Screen Scaling Filter = Фильтр масштабирования экрана
Show Debug Statistics = Отображать отладочную информацию
Show FPS Counter = Показывать счетчик FPS
Skip GPU Readbacks = Skip GPU Readbacks
Skip GPU Readbacks = Пропускать чтение данных ГП
Software Rendering = Программный рендеринг (медленно)
Software Skinning = Программная заливка
SoftwareSkinning Tip = Объединяет вызовы отрисовки моделей с заливкой на ЦП, быстрее во многих играх
Speed = Скорость
Speed Hacks = Speed Hacks (могут вызывать глюки)
Stereo display shader = Stereo display shader
Stereo rendering = Stereo rendering
Stereo display shader = Шейдер стереодисплея
Stereo rendering = Стереорендеринг
Stretch = Растягивание
Texture Filter = Текстурный фильтр
Texture Filtering = Фильтрация текстур
Texture Scaling = Масштабирование текстур
Texture Shader = Текстурный шейдер
Turn off Hardware Tessellation - unsupported = Выключите "аппаратную тесселяцию": не поддерживается
Turn off Hardware Tessellation - unsupported = Выключите настройку "Аппаратная тесселяция": не поддерживается
Unlimited = Без ограничений
Up to 1 = До 1
Up to 2 = До 2
@ -581,8 +580,8 @@ Zip archive corrupt = ZIP-архив повреждён
Zip file does not contain PSP software = В ZIP-файле отсутсвует ПО для PSP
[KeyMapping]
Autoconfigure = Авто конфиг
Autoconfigure for device = Авто конфиг для устройства
Autoconfigure = Автоконфиг
Autoconfigure for device = Автоконфиг для устройства
Bind All = Настроить всё
Clear All = Очистить все
Default All = По умолчанию
@ -722,8 +721,8 @@ Center Left = В центре слева
Center Right = В центре справа
Change Mac Address = Изменить MAC-адрес
Change proAdhocServer Address = Изменить IP-адрес ad-hoc сервера (localhost = множество экземпляров)
ChangeMacSaveConfirm = Generate a new MAC address?
ChangeMacSaveWarning = Some games verify the MAC address when loading savedata, so this may break old saves.
ChangeMacSaveConfirm = Сгенерировать новый MAC-адрес?
ChangeMacSaveWarning = Некоторые игры проверяют MAC-адрес при загрузке сохранений, из-за этого старые сохранения могут быть испорчены.
Chat = Чат
Chat Button Position = Позиция кнопки чата
Chat Here = Чат здесь
@ -747,7 +746,7 @@ Failed to Bind Localhost IP = Не удалось привязать адрес
Failed to Bind Port = Не удалось привязать порт
Failed to connect to Adhoc Server = Не удалось подключиться к ad-hoc серверу
Forced First Connect = Принудительное первое подключение (быстрое подключение)
GM: Data from Unknown Port = GM: Данные от неизвестного порта
GM: Data from Unknown Port = GM: Данные с неизвестного порта
Hostname = Имя хоста
Invalid IP or hostname = Некорректный IP или имя хоста
Minimum Timeout = Минимальный таймаут (задержка в мс, 0 = по умолчанию)
@ -804,9 +803,9 @@ Black border = Черные рамки
Bloom = Свечение
Brightness = Яркость
Cartoon = Мультипликация
CatmullRom = Бикубический (Catmull-Rom) Апскейлер
CatmullRom = Бикубический (Catmull-Rom) апскейлер
ColorCorrection = Цветокоррекция
ColorPreservation = Color preservation
ColorPreservation = Сохранение цвета
Contrast = Контрастность
CRT = ЭЛТ-развертка
FXAA = Сглаживание FXAA
@ -815,13 +814,13 @@ Grayscale = Оттенки серого
GreenLevel = GreenLevel
Intensity = Интенсивность
InverseColors = Инвертированные цвета
MitchellNetravali = Бикубический (Mitchell-Netravali) Апскейлер
MitchellNetravali = Бикубический (Mitchell-Netravali) апскейлер
Natural = Естественные цвета
NaturalA = Естественные цвета (без размытия)
Off = Выключена
Power = Сила
PSPColor = Цвета PSP
RedBlue = Red/Blue glasses
RedBlue = Красно-синие очки
Saturation = Насыщенность
Scanlines = Строки развертки (ЭЛТ)
Sharpen = Резкость
@ -1043,10 +1042,10 @@ CPU Name = Название
D3DCompiler Version = Версия D3DCompiler
Debug = Отладочная
Debugger Present = Отладчик присутствует
#Depth buffer format = Формат буфера глубины
Depth buffer format = Формат буфера глубины
Device Info = Устройство
Directories = Директории
Display Color Formats = Display Color Formats
Display Color Formats = Форматы цветов дисплея
Display Information = Информация о дисплее
Driver bugs = Ошибки драйвера
Driver Version = Версия драйвера
@ -1096,7 +1095,7 @@ Cache ISO in RAM = Кэшировать ISO в ОЗУ
Change CPU Clock = Эмулируемая частота ЦП PSP (нестабильно)
Color Saturation = Насыщенность
Color Tint = Оттенок цвета
Game crashed = Game crashed
Game crashed = Игра вылетела
Language = Язык
Memory Stick folder = Изменить папку с картой памяти
Memory Stick size = Изменить размер карты памяти (Гб)

@ -1 +1 @@
Subproject commit a886587cc29ffadc93f5533a0f8dc329ae355b9a
Subproject commit 46065027500cd781ce7c15c051c8b0c4751ad1fa

View File

@ -191,6 +191,9 @@ tests_good = [
"gpu/texfunc/replace",
"gpu/textures/mipmap",
"gpu/textures/rotate",
"gpu/transfer/invalid",
"gpu/transfer/mirrors",
"gpu/transfer/overlap",
"gpu/vertices/colors",
"gpu/vertices/morph",
"gpu/vertices/texcoords",