Merge branch 'master' into TemporaryHackishBranch

This commit is contained in:
LunaMoo committed 2017-11-14 11:13:03 +01:00
commit c7cddb93fa
37 files changed
+409 -921

No files matched your search

+13 -2
View File
@@ -34,6 +34,10 @@ extern "C" {
#include "GPU/Common/GPUDebugInterface.h"
#include "Core/ELF/ParamSFO.h"
#include "Core/HLE/sceKernelTime.h"
#include "StringUtils.h"
#ifdef USE_FFMPEG
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1)
@@ -86,10 +90,16 @@ bool AVIDump::CreateAVI() {
#ifdef USE_FFMPEG
AVCodec* codec = nullptr;
// Use gameID_EmulatedTimestamp for filename
std::string discID = g_paramSFO.GetDiscID();
std::string video_file_name = StringFromFormat("%s%s_%s.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str();
s_format_context = avformat_alloc_context();
std::stringstream s_file_index_str;
s_file_index_str << s_file_index;
snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", (GetSysDirectory(DIRECTORY_VIDEO) + "framedump" + s_file_index_str.str() + ".avi").c_str());
s_file_index_str << video_file_name;
snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", s_file_index_str.str().c_str());
INFO_LOG(COMMON, "Recording Video to: %s", s_format_context->filename);
// Make sure that the path exists
if (!File::Exists(GetSysDirectory(DIRECTORY_VIDEO)))
File::CreateDir(GetSysDirectory(DIRECTORY_VIDEO));
@@ -214,6 +224,7 @@ void AVIDump::AddFrame()
if (error)
ERROR_LOG(G3D, "Error while encoding video: %d", error);
#endif
delete[] flipbuffer;
}
void AVIDump::Stop() {
+1
View File
@@ -361,6 +361,7 @@ static ConfigSetting generalSettings[] = {
ConfigSetting("UseFFV1", &g_Config.bUseFFV1, false),
ConfigSetting("DumpFrames", &g_Config.bDumpFrames, false),
ConfigSetting("DumpAudio", &g_Config.bDumpAudio, false),
ConfigSetting("SaveLoadResetsAVdumping", &g_Config.bSaveLoadResetsAVdumping, false),
ConfigSetting("StateSlot", &g_Config.iCurrentStateSlot, 0, true, true),
ConfigSetting("RewindFlipFrequency", &g_Config.iRewindFlipFrequency, 0, true, true),
+1
View File
@@ -105,6 +105,7 @@ public:
bool bUseFFV1;
bool bDumpFrames;
bool bDumpAudio;
bool bSaveLoadResetsAVdumping;
bool bEnableLogging;
bool bDumpDecryptedEboot;
bool bFullscreenOnDoubleclick;
+24 -3
View File
@@ -35,6 +35,9 @@
#include "Core/System.h"
#ifndef MOBILE_DEVICE
#include "Core/WaveFile.h"
#include "Core/ELF/ParamSFO.h"
#include "Core/HLE/sceKernelTime.h"
#include "StringUtils.h"
#endif
#include "Core/HLE/__sceAudio.h"
#include "Core/HLE/sceAudio.h"
@@ -332,7 +335,7 @@ void __AudioSetOutputFrequency(int freq) {
// Mix samples from the various audio channels into a single sample queue.
// This single sample queue is where __AudioMix should read from. If the sample queue is full, we should
// just sleep the main emulator thread a little.
void __AudioUpdate() {
void __AudioUpdate(bool resetRecording) {
// Audio throttle doesn't really work on the PSP since the mixing intervals are so closely tied
// to the CPU. Much better to throttle the frame rate on frame display and just throw away audio
// if the buffer somehow gets full.
@@ -385,11 +388,25 @@ void __AudioUpdate() {
if (g_Config.bEnableSound) {
resampler.PushSamples(mixBuffer, hwBlockSize);
#ifndef MOBILE_DEVICE
if (g_Config.bSaveLoadResetsAVdumping && resetRecording) {
__StopLogAudio();
std::string discID = g_paramSFO.GetDiscID();
std::string audio_file_name = StringFromFormat("%s%s_%s.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str();
INFO_LOG(COMMON, "Restarted audio recording to: %s", audio_file_name.c_str());
if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO)))
File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO));
File::CreateEmptyFile(audio_file_name);
__StartLogAudio(audio_file_name);
}
if (!m_logAudio) {
if (g_Config.bDumpAudio) {
std::string audio_file_name = GetSysDirectory(DIRECTORY_AUDIO) + "audiodump.wav";
// Use gameID_EmulatedTimestamp for filename
std::string discID = g_paramSFO.GetDiscID();
std::string audio_file_name = StringFromFormat("%s%s_%s.wav", GetSysDirectory(DIRECTORY_AUDIO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str();
INFO_LOG(COMMON,"Recording audio to: %s", audio_file_name.c_str());
// Create the path just in case it doesn't exist
File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO));
if (!File::Exists(GetSysDirectory(DIRECTORY_AUDIO)))
File::CreateDir(GetSysDirectory(DIRECTORY_AUDIO));
File::CreateEmptyFile(audio_file_name);
__StartLogAudio(audio_file_name);
}
@@ -447,3 +464,7 @@ void __StopLogAudio() {
}
}
#endif
void WAVDump::Reset() {
__AudioUpdate(true);
}
+7 -1
View File
@@ -33,7 +33,7 @@ struct AudioDebugStats {
void __AudioInit();
void __AudioDoState(PointerWrap &p);
void __AudioUpdate();
void __AudioUpdate(bool resetRecording = false);
void __AudioShutdown();
void __AudioSetOutputFrequency(int freq);
@@ -49,3 +49,9 @@ void __PushExternalAudio(const s32 *audio, int numSamples); // Should not be us
// Audio Dumping stuff
void __StartLogAudio(const std::string& filename);
void __StopLogAudio();
class WAVDump
{
public:
static void Reset();
};
+17
View File
@@ -31,6 +31,7 @@
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceRtc.h"
#include "Core/MemMap.h"
#include "StringUtils.h"
// The time when the game started.
static time_t start_time;
@@ -171,3 +172,19 @@ u32 sceKernelLibcGettimeofday(u32 timeAddr, u32 tzAddr)
hleReSchedule("libc timeofday");
return 0;
}
std::string KernelTimeNowFormatted() {
time_t emulatedTime = (time_t)start_time + (u32)(CoreTiming::GetGlobalTimeUs() / 1000000ULL);
tm* timePtr = localtime(&emulatedTime);
bool DST = timePtr->tm_isdst;
u8 seconds = timePtr->tm_sec;
u8 minutes = timePtr->tm_min;
u8 hours = timePtr->tm_hour;
if (DST)
hours = timePtr->tm_hour + 1;
u8 days = timePtr->tm_mday;
u8 months = timePtr->tm_mon + 1;
u16 years = timePtr->tm_year + 1900;
std::string timestamp = StringFromFormat("%04d-%02d-%02d_%02d-%02d-%02d", years, months, days, hours, minutes, seconds);
return timestamp;
}
+1
View File
@@ -27,6 +27,7 @@ int sceKernelSysClock2USec(u32 sysclockPtr, u32 highPtr, u32 lowPtr);
int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 highPtr);
u64 sceKernelUSec2SysClockWide(u32 usec);
u32 sceKernelLibcClock();
std::string KernelTimeNowFormatted();
void __KernelTimeInit();
void __KernelTimeDoState(PointerWrap &p);
+27
View File
@@ -47,6 +47,11 @@
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"
#ifndef MOBILE_DEVICE
#include "Core/AVIDump.h"
#include "Core/HLE/__sceAudio.h"
#endif
namespace SaveState
{
struct SaveStart
@@ -592,6 +597,17 @@ namespace SaveState
callbackMessage = sc->T("Loaded State");
callbackResult = true;
hasLoadedState = true;
#ifndef MOBILE_DEVICE
if (g_Config.bSaveLoadResetsAVdumping) {
if (g_Config.bDumpFrames) {
AVIDump::Stop();
AVIDump::Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
}
if (g_Config.bDumpAudio) {
WAVDump::Reset();
}
}
#endif
} else if (result == CChunkFileReader::ERROR_BROKEN_STATE) {
HandleFailure();
callbackMessage = i18nLoadFailure;
@@ -616,6 +632,17 @@ namespace SaveState
if (result == CChunkFileReader::ERROR_NONE) {
callbackMessage = sc->T("Saved State");
callbackResult = true;
#ifndef MOBILE_DEVICE
if (g_Config.bSaveLoadResetsAVdumping) {
if (g_Config.bDumpFrames) {
AVIDump::Stop();
AVIDump::Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
}
if (g_Config.bDumpAudio) {
WAVDump::Reset();
}
}
#endif
} else if (result == CChunkFileReader::ERROR_BROKEN_STATE) {
HandleFailure();
callbackMessage = i18nSaveFailure;
+4 -11
View File
@@ -1173,18 +1173,11 @@ void TextureCacheCommon::DecodeTextureLevel(u8 *out, int outPitch, GETextureForm
memcpy(out + outPitch * y, texptr + bufw * sizeof(u16) * y, w * sizeof(u16));
}
}
} else if (h >= 8) {
} else if (h >= 8 && !expandTo32bit) {
// Note: this is always safe since h must be a power of 2, so a multiple of 8.
if (!expandTo32bit) {
UnswizzleFromMem((u32 *)out, outPitch, texptr, bufw, h, 2);
if (reverseColors) {
ReverseColors(out, out, format, h * outPitch / 2, useBGRA);
}
} else if (expandTo32bit) {
UnswizzleFromMem((u32 *)out, outPitch / 2, texptr, bufw, h, 2);
for (int y = h - 1; y >= 0; --y) {
ConvertFormatToRGBA8888(format, (u32 *)(out + outPitch * y), (const u16 *)(out + outPitch / 2 * y), w);
}
UnswizzleFromMem((u32 *)out, outPitch, texptr, bufw, h, 2);
if (reverseColors) {
ReverseColors(out, out, format, h * outPitch / 2, useBGRA);
}
} else {
// We don't have enough space for all rows in out, so use a temp buffer.
+6 -2
View File
@@ -73,13 +73,15 @@ int DecFmtSize(u8 fmt) {
case DEC_U16_2: return 4;
case DEC_U16_3: return 8;
case DEC_U16_4: return 8;
case DEC_U8A_2: return 4;
case DEC_U16A_2: return 4;
default:
return 0;
}
}
void DecVtxFormat::ComputeID() {
id = w0fmt | (w1fmt << 4) | (uvfmt << 8) | (c0fmt << 12) | (c1fmt << 16) | (nrmfmt << 20) | (posfmt << 24);
}
void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound) {
// Find index bounds. Could cache this in display lists.
// Also, this could be greatly sped up with SSE2/NEON, although rarely a bottleneck.
@@ -1152,6 +1154,8 @@ void VertexDecoder::SetVertexType(u32 fmt, const VertexDecoderOptions &options,
decFmt.stride = decOff;
decFmt.ComputeID();
size = align(size, biggest);
onesize_ = size;
size *= morphcount;
+4 -17
View File
@@ -43,6 +43,7 @@
// Can write code to easily bind these using OpenGL, or read these manually.
// No morph support, that is taken care of by the VertexDecoder.
// Keep this in 4 bits.
enum {
DEC_NONE,
DEC_FLOAT_1,
@@ -59,8 +60,6 @@ enum {
DEC_U16_2,
DEC_U16_3,
DEC_U16_4,
DEC_U8A_2,
DEC_U16A_2,
};
int DecFmtSize(u8 fmt);
@@ -74,6 +73,9 @@ struct DecVtxFormat {
u8 nrmfmt; u8 nrmoff;
u8 posfmt; u8 posoff;
short stride;
uint32_t id;
void ComputeID();
};
struct TransformedVertex
@@ -297,21 +299,6 @@ public:
}
break;
case DEC_U8A_2:
{
const u8 *b = (const u8 *)(data_ + decFmt_.uvoff);
uv[0] = (float)b[0];
uv[1] = (float)b[1];
}
break;
case DEC_U16A_2:
{
const u16 *p = (const u16 *)(data_ + decFmt_.uvoff);
uv[0] = (float)p[0];
uv[1] = (float)p[1];
}
break;
default:
ERROR_LOG_REPORT_ONCE(fmtuv, G3D, "Reader: Unsupported UV Format %d", decFmt_.uvfmt);
memset(uv, 0, sizeof(float) * 2);
+2 -20
View File
@@ -175,8 +175,6 @@ static const DeclTypeInfo VComp[] = {
{ DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16_2" }, // DEC_U16_2,
{ DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3,
{ DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4,
{ DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U8A_2"}, // DEC_U8A_2,
{ DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16A_2" }, // DEC_U16A_2,
};
static void VertexAttribSetup(D3D11_INPUT_ELEMENT_DESC * VertexElement, u8 fmt, u8 offset, const char *semantic, u8 semantic_index = 0) {
@@ -190,7 +188,7 @@ static void VertexAttribSetup(D3D11_INPUT_ELEMENT_DESC * VertexElement, u8 fmt,
ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshader, const DecVtxFormat &decFmt, u32 pspFmt) {
// TODO: Instead of one for each vshader, we can reduce it to one for each type of shader
// that reads TEXCOORD or not, etc. Not sure if worth it.
InputLayoutKey key{ vshader, pspFmt };
InputLayoutKey key{ vshader, decFmt.id };
ID3D11InputLayout *inputLayout = inputLayoutMap_.Get(key);
if (inputLayout) {
return inputLayout;
@@ -251,22 +249,6 @@ ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshade
}
}
void DrawEngineD3D11::SetupVertexDecoder(u32 vertType) {
SetupVertexDecoderInternal(vertType);
}
inline void DrawEngineD3D11::SetupVertexDecoderInternal(u32 vertType) {
// As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it
// into the top of the verttype where there are unused bits.
const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24);
// If vtype has changed, setup the vertex decoder.
if (vertTypeID != lastVType_) {
dec_ = GetVertexDecoder(vertTypeID);
lastVType_ = vertTypeID;
}
}
void DrawEngineD3D11::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) {
if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX)
Flush();
@@ -278,7 +260,7 @@ void DrawEngineD3D11::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim,
prevPrim_ = prim;
}
SetupVertexDecoderInternal(vertType);
SetupVertexDecoder(vertType);
*bytesRead = vertexCount * dec_->VertexSize();
+3 -6
View File
@@ -121,9 +121,6 @@ public:
void BeginFrame();
void SetupVertexDecoder(u32 vertType);
void SetupVertexDecoderInternal(u32 vertType);
// So that this can be inlined
void Flush() {
if (!numDrawCalls)
@@ -170,11 +167,11 @@ private:
struct InputLayoutKey {
D3D11VertexShader *vshader;
u32 vertType;
u32 decFmtId;
bool operator <(const InputLayoutKey &other) const {
if (vertType < other.vertType)
if (decFmtId < other.decFmtId)
return true;
if (vertType > other.vertType)
if (decFmtId > other.decFmtId)
return false;
return vshader < other.vshader;
}
+6 -185
View File
@@ -76,16 +76,16 @@ struct D3D11CommandTableEntry {
// This table gets crunched into a faster form by init.
static const D3D11CommandTableEntry commandTable[] = {
// Changes that dirty the current texture.
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_TexSize0 },
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_TexSize0 },
{ GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_FOGCOEF | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE }, // These are combined in D3D11
// Changing the vertex type requires us to flush.
{ GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_D3D11::Execute_VertexType },
{ GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_VertexType },
{ GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Prim },
{ GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Bezier },
{ GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Spline },
{ GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier },
{ GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Spline },
// Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack...
{ GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_LoadClut },
@@ -202,10 +202,10 @@ GPU_D3D11::~GPU_D3D11() {
void GPU_D3D11::UpdateCmdInfo() {
if (g_Config.bSoftwareSkinning) {
cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_D3D11::Execute_VertexTypeSkinning;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexTypeSkinning;
} else {
cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_D3D11::Execute_VertexType;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType;
}
CheckGPUFeatures();
@@ -443,37 +443,6 @@ void GPU_D3D11::ExecuteOp(u32 op, u32 diff) {
}
}
void GPU_D3D11::Execute_VertexType(u32 op, u32 diff) {
if (diff)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) {
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
}
void GPU_D3D11::Execute_VertexTypeSkinning(u32 op, u32 diff) {
// Don't flush when weight count changes, unless morph is enabled.
if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
// Restore and flush
gstate.vertType ^= diff;
Flush();
gstate.vertType ^= diff;
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK))
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// In this case, we may be doing weights and morphs.
// Update any bone matrix uniforms so it uses them correctly.
if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
gstate_c.Dirty(gstate_c.deferredVertTypeDirty);
gstate_c.deferredVertTypeDirty = 0;
}
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
}
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
void GPU_D3D11::Execute_Prim(u32 op, u32 diff) {
// This drives all drawing. All other state we just buffer up, then we apply it only
// when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization.
@@ -547,154 +516,6 @@ void GPU_D3D11::Execute_Prim(u32 op, u32 diff) {
AdvanceVerts(vertexType, count, bytesRead);
}
void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) {
Flush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManagerD3D11_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
}
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
return;
}
void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
void *indices = NULL;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
return;
}
indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
}
if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) {
DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT);
}
if (vertTypeIsSkinningEnabled(gstate.vertType)) {
DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType));
}
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim));
int bz_ucount = op & 0xFF;
int bz_vcount = (op >> 8) & 0xFF;
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = true;
if (gstate_c.spline_count_u != bz_ucount) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_count_u = bz_ucount;
}
}
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
if (gstate_c.bezier)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = false;
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = bz_ucount * bz_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_D3D11::Execute_Spline(u32 op, u32 diff) {
Flush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManagerD3D11_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
}
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
return;
}
void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
void *indices = NULL;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
return;
}
indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
}
if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) {
DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT);
}
if (vertTypeIsSkinningEnabled(gstate.vertType)) {
DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType));
}
int sp_ucount = op & 0xFF;
int sp_vcount = (op >> 8) & 0xFF;
int sp_utype = (op >> 16) & 0x3;
int sp_vtype = (op >> 18) & 0x3;
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim));
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
u32 vertType = gstate.vertType;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = true;
bool countsChanged = gstate_c.spline_count_u != sp_ucount || gstate_c.spline_count_v != sp_vcount;
bool typesChanged = gstate_c.spline_type_u != sp_utype || gstate_c.spline_type_v != sp_vtype;
if (countsChanged || typesChanged) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_count_u = sp_ucount;
gstate_c.spline_count_v = sp_vcount;
gstate_c.spline_type_u = sp_utype;
gstate_c.spline_type_v = sp_vtype;
}
}
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead);
if (gstate_c.spline)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = false;
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = sp_ucount * sp_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_D3D11::Execute_TexSize0(u32 op, u32 diff) {
// Render to texture may have overridden the width/height.
// Don't reset it unless the size is different / the texture has changed.
if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) {
gstate_c.curTextureWidth = gstate.getTextureWidth(0);
gstate_c.curTextureHeight = gstate.getTextureHeight(0);
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// We will need to reset the texture now.
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
}
}
void GPU_D3D11::Execute_LoadClut(u32 op, u32 diff) {
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
textureCacheD3D11_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes());
-5
View File
@@ -68,11 +68,6 @@ public:
};
void Execute_Prim(u32 op, u32 diff);
void Execute_Bezier(u32 op, u32 diff);
void Execute_Spline(u32 op, u32 diff);
void Execute_VertexType(u32 op, u32 diff);
void Execute_VertexTypeSkinning(u32 op, u32 diff);
void Execute_TexSize0(u32 op, u32 diff);
void Execute_LoadClut(u32 op, u32 diff);
// Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
-3
View File
@@ -155,9 +155,6 @@ static const DeclTypeInfo VComp[] = {
{0, "UNUSED_DEC_U16_2" }, // DEC_U16_2,
{D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3,
{D3DDECLTYPE_USHORT4N ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4,
// Not supported in regular DX9 so faking, will cause graphics bugs until worked around
{0,"UNUSED_DEC_U8A_2"}, // DEC_U8A_2,
{0,"UNUSED_DEC_U16A_2" }, // DEC_U16A_2,
};
static void VertexAttribSetup(D3DVERTEXELEMENT9 * VertexElement, u8 fmt, u8 offset, u8 usage, u8 usage_index = 0) {
+6 -152
View File
@@ -60,16 +60,16 @@ struct D3D9CommandTableEntry {
// This table gets crunched into a faster form by init.
static const D3D9CommandTableEntry commandTable[] = {
// Changes that dirty the current texture.
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_TexSize0 },
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_TexSize0 },
{ GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE },
// Changing the vertex type requires us to flush.
{ GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_DX9::Execute_VertexType },
{ GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_VertexType },
{ GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_DX9::Execute_Prim },
{ GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_Bezier },
{ GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_Spline },
{ GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier },
{ GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Spline },
// Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack...
{ GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_DX9::Execute_LoadClut },
@@ -171,10 +171,10 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
void GPU_DX9::UpdateCmdInfo() {
if (g_Config.bSoftwareSkinning) {
cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_DX9::Execute_VertexTypeSkinning;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexTypeSkinning;
} else {
cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_DX9::Execute_VertexType;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType;
}
CheckGPUFeatures();
@@ -408,37 +408,6 @@ void GPU_DX9::ExecuteOp(u32 op, u32 diff) {
}
}
void GPU_DX9::Execute_VertexType(u32 op, u32 diff) {
if (diff)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) {
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
}
}
void GPU_DX9::Execute_VertexTypeSkinning(u32 op, u32 diff) {
// Don't flush when weight count changes, unless morph is enabled.
if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
// Restore and flush
gstate.vertType ^= diff;
Flush();
gstate.vertType ^= diff;
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK))
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// In this case, we may be doing weights and morphs.
// Update any bone matrix uniforms so it uses them correctly.
if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
gstate_c.Dirty(gstate_c.deferredVertTypeDirty);
gstate_c.deferredVertTypeDirty = 0;
}
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
}
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
}
void GPU_DX9::Execute_Prim(u32 op, u32 diff) {
// This drives all drawing. All other state we just buffer up, then we apply it only
// when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization.
@@ -511,121 +480,6 @@ void GPU_DX9::Execute_Prim(u32 op, u32 diff) {
AdvanceVerts(vertexType, count, bytesRead);
}
void GPU_DX9::Execute_Bezier(u32 op, u32 diff) {
Flush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManagerDX9_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
}
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
return;
}
void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
void *indices = NULL;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
return;
}
indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
}
if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) {
DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT);
}
if (vertTypeIsSkinningEnabled(gstate.vertType)) {
DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType));
}
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim));
int bz_ucount = op & 0xFF;
int bz_vcount = (op >> 8) & 0xFF;
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = bz_ucount * bz_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_DX9::Execute_Spline(u32 op, u32 diff) {
Flush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManagerDX9_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
}
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
return;
}
void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
void *indices = NULL;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
return;
}
indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
}
if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) {
DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT);
}
if (vertTypeIsSkinningEnabled(gstate.vertType)) {
DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType));
}
int sp_ucount = op & 0xFF;
int sp_vcount = (op >> 8) & 0xFF;
int sp_utype = (op >> 16) & 0x3;
int sp_vtype = (op >> 18) & 0x3;
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim));
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
u32 vertType = gstate.vertType;
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead);
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = sp_ucount * sp_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_DX9::Execute_TexSize0(u32 op, u32 diff) {
// Render to texture may have overridden the width/height.
// Don't reset it unless the size is different / the texture has changed.
if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) {
gstate_c.curTextureWidth = gstate.getTextureWidth(0);
gstate_c.curTextureHeight = gstate.getTextureHeight(0);
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// We will need to reset the texture now.
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
}
}
void GPU_DX9::Execute_LoadClut(u32 op, u32 diff) {
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
textureCacheDX9_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes());
-4
View File
@@ -69,10 +69,6 @@ public:
};
void Execute_Prim(u32 op, u32 diff);
void Execute_Bezier(u32 op, u32 diff);
void Execute_Spline(u32 op, u32 diff);
void Execute_VertexType(u32 op, u32 diff);
void Execute_VertexTypeSkinning(u32 op, u32 diff);
void Execute_TexSize0(u32 op, u32 diff);
void Execute_LoadClut(u32 op, u32 diff);
-2
View File
@@ -228,8 +228,6 @@ static const GlTypeInfo GLComp[] = {
{GL_UNSIGNED_SHORT, 2, GL_TRUE},// DEC_U16_2,
{GL_UNSIGNED_SHORT, 3, GL_TRUE},// DEC_U16_3,
{GL_UNSIGNED_SHORT, 4, GL_TRUE},// DEC_U16_4,
{GL_UNSIGNED_BYTE, 2, GL_FALSE},// DEC_U8A_2,
{GL_UNSIGNED_SHORT, 2, GL_FALSE},// DEC_U16A_2,
};
static inline void VertexAttribSetup(int attrib, int fmt, int stride, u8 *ptr) {
+6 -184
View File
@@ -63,16 +63,16 @@ struct GLESCommandTableEntry {
// TODO: Share this table between the backends. Will have to make another indirection for the function pointers though..
static const GLESCommandTableEntry commandTable[] = {
// Changes that dirty the current texture.
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, DIRTY_UVSCALEOFFSET, &GPU_GLES::Execute_TexSize0 },
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_TexSize0 },
{ GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE },
// Changing the vertex type requires us to flush.
{ GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_GLES::Execute_VertexType },
{ GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_VertexType },
{ GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_GLES::Execute_Prim },
{ GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_GLES::Execute_Bezier },
{ GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_GLES::Execute_Spline },
{ GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier },
{ GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Spline },
// Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack...
{ GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_GLES::Execute_LoadClut },
@@ -461,10 +461,10 @@ inline void GPU_GLES::UpdateVsyncInterval(bool force) {
void GPU_GLES::UpdateCmdInfo() {
if (g_Config.bSoftwareSkinning) {
cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_GLES::Execute_VertexTypeSkinning;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexTypeSkinning;
} else {
cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_GLES::Execute_VertexType;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType;
}
}
@@ -688,184 +688,6 @@ void GPU_GLES::Execute_Prim(u32 op, u32 diff) {
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_GLES::Execute_VertexType(u32 op, u32 diff) {
if (diff)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) {
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
}
void GPU_GLES::Execute_VertexTypeSkinning(u32 op, u32 diff) {
// Don't flush when weight count changes, unless morph is enabled.
if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
// Restore and flush
gstate.vertType ^= diff;
Flush();
gstate.vertType ^= diff;
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK))
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// In this case, we may be doing weights and morphs.
// Update any bone matrix uniforms so it uses them correctly.
if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
gstate_c.Dirty(gstate_c.deferredVertTypeDirty);
gstate_c.deferredVertTypeDirty = 0;
}
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
}
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
void GPU_GLES::Execute_Bezier(u32 op, u32 diff) {
Flush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManagerGL_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
}
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
return;
}
void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
void *indices = NULL;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
return;
}
indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
}
if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) {
DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT);
}
if (vertTypeIsSkinningEnabled(gstate.vertType)) {
DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType));
}
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim));
int bz_ucount = op & 0xFF;
int bz_vcount = (op >> 8) & 0xFF;
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = true;
if (gstate_c.spline_count_u != bz_ucount) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_count_u = bz_ucount;
}
}
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
if (gstate_c.bezier)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = false;
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = bz_ucount * bz_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_GLES::Execute_Spline(u32 op, u32 diff) {
Flush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManagerGL_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
}
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
return;
}
void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
void *indices = NULL;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
return;
}
indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
}
if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) {
DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT);
}
if (vertTypeIsSkinningEnabled(gstate.vertType)) {
DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType));
}
int sp_ucount = op & 0xFF;
int sp_vcount = (op >> 8) & 0xFF;
int sp_utype = (op >> 16) & 0x3;
int sp_vtype = (op >> 18) & 0x3;
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim));
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
u32 vertType = gstate.vertType;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = true;
bool countsChanged = gstate_c.spline_count_u != sp_ucount || gstate_c.spline_count_v != sp_vcount;
bool typesChanged = gstate_c.spline_type_u != sp_utype || gstate_c.spline_type_v != sp_vtype;
if (countsChanged || typesChanged) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_count_u = sp_ucount;
gstate_c.spline_count_v = sp_vcount;
gstate_c.spline_type_u = sp_utype;
gstate_c.spline_type_v = sp_vtype;
}
}
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead);
if (gstate_c.spline)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = false;
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = sp_ucount * sp_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_GLES::Execute_TexSize0(u32 op, u32 diff) {
// Render to texture may have overridden the width/height.
// Don't reset it unless the size is different / the texture has changed.
if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) {
gstate_c.curTextureWidth = gstate.getTextureWidth(0);
gstate_c.curTextureHeight = gstate.getTextureHeight(0);
gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_TEXTURE_PARAMS);
}
}
void GPU_GLES::Execute_LoadClut(u32 op, u32 diff) {
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
textureCacheGL_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes());
-5
View File
@@ -71,12 +71,7 @@ public:
};
void Execute_Prim(u32 op, u32 diff);
void Execute_Bezier(u32 op, u32 diff);
void Execute_Spline(u32 op, u32 diff);
void Execute_LoadClut(u32 op, u32 diff);
void Execute_VertexType(u32 op, u32 diff);
void Execute_VertexTypeSkinning(u32 op, u32 diff);
void Execute_TexSize0(u32 op, u32 diff);
// Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override;
+91 -2
View File
@@ -1329,8 +1329,55 @@ void GPUCommon::Execute_TexLevel(u32 op, u32 diff) {
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS | DIRTY_FRAGMENTSHADER_STATE);
}
void GPUCommon::Execute_TexSize0(u32 op, u32 diff) {
// Render to texture may have overridden the width/height.
// Don't reset it unless the size is different / the texture has changed.
if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) {
gstate_c.curTextureWidth = gstate.getTextureWidth(0);
gstate_c.curTextureHeight = gstate.getTextureHeight(0);
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// We will need to reset the texture now.
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
}
}
void GPUCommon::Execute_VertexType(u32 op, u32 diff) {
if (diff)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) {
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
}
void GPUCommon::Execute_VertexTypeSkinning(u32 op, u32 diff) {
// Don't flush when weight count changes, unless morph is enabled.
if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
// Restore and flush
gstate.vertType ^= diff;
Flush();
gstate.vertType ^= diff;
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK))
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// In this case, we may be doing weights and morphs.
// Update any bone matrix uniforms so it uses them correctly.
if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
gstate_c.Dirty(gstate_c.deferredVertTypeDirty);
gstate_c.deferredVertTypeDirty = 0;
}
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
}
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
void GPUCommon::Execute_Bezier(u32 op, u32 diff) {
Flush();
drawEngineCommon_->DispatchFlush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
@@ -1361,20 +1408,41 @@ void GPUCommon::Execute_Bezier(u32 op, u32 diff) {
}
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim));
int bz_ucount = op & 0xFF;
int bz_vcount = (op >> 8) & 0xFF;
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = true;
if (gstate_c.spline_count_u != bz_ucount) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_count_u = bz_ucount;
}
}
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngineCommon_->SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
if (gstate_c.bezier)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = false;
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = bz_ucount * bz_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPUCommon::Execute_Spline(u32 op, u32 diff) {
Flush();
drawEngineCommon_->DispatchFlush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
@@ -1409,12 +1477,33 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) {
int sp_utype = (op >> 16) & 0x3;
int sp_vtype = (op >> 18) & 0x3;
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim));
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
u32 vertType = gstate.vertType;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = true;
bool countsChanged = gstate_c.spline_count_u != sp_ucount || gstate_c.spline_count_v != sp_vcount;
bool typesChanged = gstate_c.spline_type_u != sp_utype || gstate_c.spline_type_v != sp_vtype;
if (countsChanged || typesChanged) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_count_u = sp_ucount;
gstate_c.spline_count_v = sp_vcount;
gstate_c.spline_type_u = sp_utype;
gstate_c.spline_type_v = sp_vtype;
}
}
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngineCommon_->SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead);
if (gstate_c.spline)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = false;
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = sp_ucount * sp_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
+7 -1
View File
@@ -100,11 +100,15 @@ public:
void Execute_Ret(u32 op, u32 diff);
void Execute_End(u32 op, u32 diff);
void Execute_VertexType(u32 op, u32 diff);
void Execute_VertexTypeSkinning(u32 op, u32 diff);
void Execute_Bezier(u32 op, u32 diff);
void Execute_Spline(u32 op, u32 diff);
void Execute_BoundingBox(u32 op, u32 diff);
void Execute_BlockTransferStart(u32 op, u32 diff);
void Execute_TexSize0(u32 op, u32 diff);
void Execute_TexLevel(u32 op, u32 diff);
void Execute_WorldMtxNum(u32 op, u32 diff);
@@ -125,7 +129,7 @@ public:
int EstimatePerVertexCost();
// Note: Not virtual!
inline void Flush();
void Flush();
#ifdef USE_CRT_DBG
#undef new
@@ -214,12 +218,14 @@ public:
protected:
void SetDrawType(DrawType type, GEPrimitiveType prim) {
if (type != lastDraw_) {
// We always flush when drawing splines/beziers so no need to do so here
gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_VERTEXSHADER_STATE);
lastDraw_ = type;
}
// Prim == RECTANGLES can cause CanUseHardwareTransform to flip, so we need to dirty.
// Also, culling may be affected so dirty the raster state.
if ((prim == GE_PRIM_RECTANGLES) != (lastPrim_ == GE_PRIM_RECTANGLES)) {
Flush();
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE);
lastPrim_ = prim;
}
+17 -31
View File
@@ -361,27 +361,10 @@ void DrawEngineVulkan::EndFrame() {
vertexCache_->End();
}
void DrawEngineVulkan::SetupVertexDecoder(u32 vertType) {
SetupVertexDecoderInternal(vertType);
}
inline void DrawEngineVulkan::SetupVertexDecoderInternal(u32 vertType) {
// As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it
// into the top of the verttype where there are unused bits.
const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24);
// If vtype has changed, setup the vertex decoder.
if (vertTypeID != lastVType_) {
dec_ = GetVertexDecoder(vertTypeID);
lastVType_ = vertTypeID;
}
if (!dec_)
Crash();
}
void DrawEngineVulkan::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) {
if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX)
if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX) {
Flush();
}
// TODO: Is this the right thing to do?
if (prim == GE_PRIM_KEEP_PREVIOUS) {
@@ -390,7 +373,7 @@ void DrawEngineVulkan::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim,
prevPrim_ = prim;
}
SetupVertexDecoderInternal(vertType);
SetupVertexDecoder(vertType);
*bytesRead = vertexCount * dec_->VertexSize();
if ((vertexCount < 2 && prim > 0) || (vertexCount < 3 && prim > 2 && prim != GE_PRIM_RECTANGLES))
@@ -502,7 +485,7 @@ void DrawEngineVulkan::SetLineWidth(float lineWidth) {
pipelineManager_->SetLineWidth(lineWidth);
}
VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone) {
VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone, bool tess) {
DescriptorSetKey key;
key.imageView_ = imageView;
key.sampler_ = sampler;
@@ -514,8 +497,6 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
_dbg_assert_(G3D, light != VK_NULL_HANDLE);
_dbg_assert_(G3D, bone != VK_NULL_HANDLE);
bool tess = gstate_c.bezier || gstate_c.spline;
FrameData *frame = &frame_[vulkan_->GetCurFrame()];
// See if we already have this descriptor set cached.
if (!tess) { // Don't cache descriptors for HW tessellation.
@@ -627,7 +608,7 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
vkUpdateDescriptorSets(vulkan_->GetDevice(), n, writes, 0, nullptr);
if (!(gstate_c.bezier || gstate_c.spline)) // Avoid caching when HW tessellation.
if (!tess) // Again, avoid caching when HW tessellation.
frame->descSets.Insert(key, desc);
return desc;
}
@@ -667,6 +648,8 @@ void DrawEngineVulkan::DoFlush() {
FrameData *frame = &frame_[vulkan_->GetCurFrame()];
bool tess = gstate_c.bezier || gstate_c.spline;
bool textureNeedsApply = false;
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
textureCache_->SetTexture();
@@ -881,13 +864,15 @@ void DrawEngineVulkan::DoFlush() {
}
if (!lastPipeline_ || !gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform);
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, true); // usehwtransform
_dbg_assert_msg_(G3D, vshader->UseHWTransform(), "Bad vshader");
if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, true);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, true);
if (!pipeline) {
// Already logged, let's bail out.
return;
@@ -908,7 +893,7 @@ void DrawEngineVulkan::DoFlush() {
dirtyUniforms_ |= shaderManager_->UpdateUniforms();
UpdateUBOs(frame);
VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf);
VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf, tess);
{
PROFILE_THIS_SCOPE("renderman_q");
@@ -921,7 +906,7 @@ void DrawEngineVulkan::DoFlush() {
if (useElements) {
if (!ibuf)
ibOffset = (uint32_t)frame->pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &ibuf);
int numInstances = (gstate_c.bezier || gstate_c.spline) ? numPatches : 1;
int numInstances = tess ? numPatches : 1;
renderManager->DrawIndexed(pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, numInstances, VK_INDEX_TYPE_UINT16);
} else {
renderManager->Draw(pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, vertexCount);
@@ -979,13 +964,14 @@ void DrawEngineVulkan::DoFlush() {
sampler = nullSampler_;
}
if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) {
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform);
shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false); // usehwtransform
_dbg_assert_msg_(G3D, !vshader->UseHWTransform(), "Bad vshader");
if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) {
ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_);
}
Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS;
VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, false);
VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, &dec_->decFmt, vshader, fshader, false);
if (!pipeline) {
// Already logged, let's bail out.
return;
@@ -1008,7 +994,7 @@ void DrawEngineVulkan::DoFlush() {
// Even if the first draw is through-mode, make sure we at least have one copy of these uniforms buffered
UpdateUBOs(frame);
VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf);
VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf, tess);
const uint32_t dynamicUBOOffsets[3] = {
baseUBOOffset, lightUBOOffset, boneUBOOffset,
};
+1 -4
View File
@@ -140,9 +140,6 @@ public:
void DeviceLost();
void DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw);
void SetupVertexDecoder(u32 vertType);
void SetupVertexDecoderInternal(u32 vertType);
// So that this can be inlined
void Flush() {
if (!numDrawCalls)
@@ -193,7 +190,7 @@ private:
void DoFlush();
void UpdateUBOs(FrameData *frame);
VkDescriptorSet GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone);
VkDescriptorSet GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone, bool tess);
VulkanContext *vulkan_;
Draw::DrawContext *draw_;
+6 -243
View File
@@ -58,16 +58,16 @@ GPU_Vulkan::CommandInfo GPU_Vulkan::cmdInfo_[256];
// This table gets crunched into a faster form by init.
static const VulkanCommandTableEntry commandTable[] = {
// Changes that dirty the current texture.
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_TexSize0 },
{ GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPUCommon::Execute_TexSize0 },
{ GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE },
// Changing the vertex type requires us to flush.
{ GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_Vulkan::Execute_VertexType },
{ GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_VertexType },
{ GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_Prim },
{ GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_Bezier },
{ GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_Spline },
{ GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Bezier },
{ GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPUCommon::Execute_Spline },
// Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack...
{ GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_Vulkan::Execute_LoadClut },
@@ -372,10 +372,10 @@ void GPU_Vulkan::UpdateVsyncInterval(bool force) {
void GPU_Vulkan::UpdateCmdInfo() {
if (g_Config.bSoftwareSkinning) {
cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_Vulkan::Execute_VertexTypeSkinning;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexTypeSkinning;
} else {
cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_Vulkan::Execute_VertexType;
cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPUCommon::Execute_VertexType;
}
}
@@ -555,248 +555,11 @@ void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) {
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_Vulkan::Execute_VertexType(u32 op, u32 diff) {
if (diff)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) {
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
}
void GPU_Vulkan::Execute_VertexTypeSkinning(u32 op, u32 diff) {
// Don't flush when weight count changes, unless morph is enabled.
if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
// Restore and flush
gstate.vertType ^= diff;
Flush();
gstate.vertType ^= diff;
if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK))
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// In this case, we may be doing weights and morphs.
// Update any bone matrix uniforms so it uses them correctly.
if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) {
gstate_c.Dirty(gstate_c.deferredVertTypeDirty);
gstate_c.deferredVertTypeDirty = 0;
}
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
}
if (diff & GE_VTYPE_THROUGH_MASK)
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_FRAGMENTSHADER_STATE);
}
void GPU_Vulkan::Execute_Bezier(u32 op, u32 diff) {
Flush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
}
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
return;
}
void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
void *indices = NULL;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
return;
}
indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
}
if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) {
DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT);
}
if (vertTypeIsSkinningEnabled(gstate.vertType)) {
DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType));
}
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_BEZIER, PatchPrimToPrim(patchPrim));
int bz_ucount = op & 0xFF;
int bz_vcount = (op >> 8) & 0xFF;
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = true;
if (gstate_c.spline_count_u != bz_ucount) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_count_u = bz_ucount;
}
}
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead);
if (gstate_c.bezier)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.bezier = false;
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = bz_ucount * bz_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_Vulkan::Execute_Spline(u32 op, u32 diff) {
Flush();
// We don't dirty on normal changes anymore as we prescale, but it's needed for splines/bezier.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET);
// This also make skipping drawing very effective.
framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
}
if (!Memory::IsValidAddress(gstate_c.vertexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr);
return;
}
void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
void *indices = NULL;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
return;
}
indices = Memory::GetPointerUnchecked(gstate_c.indexAddr);
}
if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) {
DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT);
}
if (vertTypeIsSkinningEnabled(gstate.vertType)) {
DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType));
}
int sp_ucount = op & 0xFF;
int sp_vcount = (op >> 8) & 0xFF;
int sp_utype = (op >> 16) & 0x3;
int sp_vtype = (op >> 18) & 0x3;
GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType();
SetDrawType(DRAW_SPLINE, PatchPrimToPrim(patchPrim));
bool computeNormals = gstate.isLightingEnabled();
bool patchFacing = gstate.patchfacing & 1;
u32 vertType = gstate.vertType;
if (g_Config.bHardwareTessellation && g_Config.bHardwareTransform && !g_Config.bSoftwareRendering) {
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = true;
bool countsChanged = gstate_c.spline_count_u != sp_ucount || gstate_c.spline_count_v != sp_vcount;
bool typesChanged = gstate_c.spline_type_u != sp_utype || gstate_c.spline_type_v != sp_vtype;
if (countsChanged || typesChanged) {
gstate_c.Dirty(DIRTY_BEZIERSPLINE);
gstate_c.spline_count_u = sp_ucount;
gstate_c.spline_count_v = sp_vcount;
gstate_c.spline_type_u = sp_utype;
gstate_c.spline_type_v = sp_vtype;
}
}
int bytesRead = 0;
UpdateUVScaleOffset();
drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead);
if (gstate_c.spline)
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
gstate_c.spline = false;
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = sp_ucount * sp_vcount;
AdvanceVerts(gstate.vertType, count, bytesRead);
}
void GPU_Vulkan::Execute_TexSize0(u32 op, u32 diff) {
// Render to texture may have overridden the width/height.
// Don't reset it unless the size is different / the texture has changed.
if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) {
gstate_c.curTextureWidth = gstate.getTextureWidth(0);
gstate_c.curTextureHeight = gstate.getTextureHeight(0);
// We will need to reset the texture now.
gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_TEXTURE_PARAMS);
}
}
void GPU_Vulkan::Execute_LoadClut(u32 op, u32 diff) {
gstate_c.Dirty(DIRTY_TEXTURE_PARAMS);
textureCacheVulkan_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes());
}
void GPU_Vulkan::Execute_BoneMtxNum(u32 op, u32 diff) {
// This is almost always followed by GE_CMD_BONEMATRIXDATA.
const u32_le *src = (const u32_le *)Memory::GetPointerUnchecked(currentList->pc + 4);
u32 *dst = (u32 *)(gstate.boneMatrix + (op & 0x7F));
const int end = 12 * 8 - (op & 0x7F);
int i = 0;
// If we can't use software skinning, we have to flush and dirty.
while ((src[i] >> 24) == GE_CMD_BONEMATRIXDATA) {
const u32 newVal = src[i] << 8;
if (dst[i] != newVal) {
Flush();
dst[i] = newVal;
}
if (++i >= end) {
break;
}
}
const int numPlusCount = (op & 0x7F) + i;
for (int num = op & 0x7F; num < numPlusCount; num += 12) {
gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12));
}
const int count = i;
gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | ((op + count) & 0x7F);
// Skip over the loaded data, it's done now.
UpdatePC(currentList->pc, currentList->pc + count * 4);
currentList->pc += count * 4;
}
void GPU_Vulkan::Execute_BoneMtxData(u32 op, u32 diff) {
// Note: it's uncommon to get here now, see above.
int num = gstate.boneMatrixNumber & 0x7F;
u32 newVal = op << 8;
if (num < 96 && newVal != ((const u32 *)gstate.boneMatrix)[num]) {
// Bone matrices should NOT flush when software skinning is enabled!
Flush();
gstate_c.Dirty(DIRTY_BONEMATRIX0 << (num / 12));
((u32 *)gstate.boneMatrix)[num] = newVal;
}
num++;
gstate.boneMatrixNumber = (GE_CMD_BONEMATRIXNUMBER << 24) | (num & 0x7F);
}
void GPU_Vulkan::FastLoadBoneMatrix(u32 target) {
const int num = gstate.boneMatrixNumber & 0x7F;
const int mtxNum = num / 12;
uint32_t uniformsToDirty = DIRTY_BONEMATRIX0 << mtxNum;
if ((num - 12 * mtxNum) != 0) {
uniformsToDirty |= DIRTY_BONEMATRIX0 << ((mtxNum + 1) & 7);
}
Flush();
gstate_c.Dirty(uniformsToDirty);
gstate.FastLoadBoneMatrix(target);
}
void GPU_Vulkan::InitDeviceObjects() {
ILOG("GPU_Vulkan::InitDeviceObjects");
// Initialize framedata
-8
View File
@@ -72,14 +72,7 @@ public:
};
void Execute_Prim(u32 op, u32 diff);
void Execute_Bezier(u32 op, u32 diff);
void Execute_Spline(u32 op, u32 diff);
void Execute_VertexType(u32 op, u32 diff);
void Execute_VertexTypeSkinning(u32 op, u32 diff);
void Execute_TexSize0(u32 op, u32 diff);
void Execute_LoadClut(u32 op, u32 diff);
void Execute_BoneMtxNum(u32 op, u32 diff);
void Execute_BoneMtxData(u32 op, u32 diff);
// Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend.
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override;
@@ -87,7 +80,6 @@ public:
protected:
void FastRunLoop(DisplayList &list) override;
void FastLoadBoneMatrix(u32 target) override;
void FinishDeferred() override;
private:
+129 -16
View File
@@ -66,9 +66,6 @@ static const DeclTypeInfo VComp[] = {
{ VK_FORMAT_R16G16_UNORM, "R16G16_UNORM" }, // DEC_U16_2,
{ VK_FORMAT_R16G16B16A16_UNORM, "R16G16B16A16_UNORM " }, // DEC_U16_3,
{ VK_FORMAT_R16G16B16A16_UNORM, "R16G16B16A16_UNORM " }, // DEC_U16_4,
{ VK_FORMAT_R8G8_UINT, "R8G8_UINT" }, // DEC_U8A_2,
{ VK_FORMAT_R16G16_UINT, "R16G16_UINT" }, // DEC_U16A_2,
};
static void VertexAttribSetup(VkVertexInputAttributeDescription *attr, int fmt, int offset, PspAttributeLocation location) {
@@ -121,7 +118,7 @@ static bool UsesBlendConstant(int factor) {
static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pipelineCache,
VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &key,
const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, float lineWidth) {
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, float lineWidth) {
bool useBlendConstant = false;
VkPipelineColorBlendAttachmentState blend0 = {};
@@ -229,10 +226,10 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
VkVertexInputAttributeDescription attrs[8];
int attributeCount;
if (useHwTransform) {
attributeCount = SetupVertexAttribs(attrs, vtxDec->decFmt);
vertexStride = vtxDec->decFmt.stride;
attributeCount = SetupVertexAttribs(attrs, *decFmt);
vertexStride = decFmt->stride;
} else {
attributeCount = SetupVertexAttribsPretransformed(attrs, vtxDec->decFmt);
attributeCount = SetupVertexAttribsPretransformed(attrs, *decFmt);
vertexStride = 36;
}
@@ -301,8 +298,8 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
return vulkanPipeline;
}
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
VulkanPipelineKey key;
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
VulkanPipelineKey key{};
if (!renderPass)
Crash();
@@ -311,7 +308,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo
key.useHWTransform = useHwTransform;
key.vShader = vs->GetModule();
key.fShader = fs->GetModule();
key.vtxDec = useHwTransform ? vtxDec : nullptr;
key.vtxDecId = useHwTransform ? decFmt->id : 0;
auto iter = pipelines_.Get(key);
if (iter)
@@ -321,7 +318,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo
VulkanPipeline *pipeline = CreateVulkanPipeline(
vulkan_->GetDevice(), pipelineCache_, layout, renderPass,
rasterKey, vtxDec, vs, fs, useHwTransform, lineWidth_);
rasterKey, decFmt, vs, fs, useHwTransform, lineWidth_);
// Even if the result is nullptr, insert it so we don't try to create it repeatedly.
pipelines_.Insert(key, pipeline);
return pipeline;
@@ -345,14 +342,75 @@ std::vector<std::string> PipelineManagerVulkan::DebugGetObjectIDs(DebugShaderTyp
return ids;
}
static const char *const topologies[8] = {
"POINTLIST",
"LINELIST",
"LINESTRIP",
"TRILIST",
"TRISTRIP",
"TRIFAN",
};
static const char *const blendOps[8] = {
"ADD",
"SUB",
"REVSUB",
"MIN",
"MAX",
};
static const char *const compareOps[8] = {
"NEVER",
"<",
"==",
"<=",
">",
">=",
"!=",
"ALWAYS",
};
static const char *const stencilOps[8] = {
"KEEP",
"ZERO",
"REPLACE",
"INC_CLAMP",
"DEC_CLAMP",
"INVERT",
"INC_WRAP",
"DEC_WRAP",
};
static const char *const blendFactors[19] = {
"ZERO",
"ONE",
"SRC_COLOR",
"ONE_MINUS_SRC_COLOR",
"DST_COLOR",
"ONE_MINUS_DST_COLOR",
"SRC_ALPHA",
"ONE_MINUS_SRC_ALPHA",
"DST_ALPHA",
"ONE_MINUS_DST_ALPHA",
"CONSTANT_COLOR",
"ONE_MINUS_CONSTANT_COLOR",
"CONSTANT_ALPHA",
"ONE_MINUS_CONSTANT_ALPHA",
"SRC_ALPHA_SATURATE",
"SRC1_COLOR",
"ONE_MINUS_SRC1_COLOR",
"SRC1_ALPHA",
"ONE_MINUS_SRC1_ALPHA",
};
std::string PipelineManagerVulkan::DebugGetObjectString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
if (type != SHADER_TYPE_PIPELINE)
return "N/A";
VulkanPipelineKey shaderId;
shaderId.FromString(id);
VulkanPipelineKey pipelineKey;
pipelineKey.FromString(id);
VulkanPipeline *iter = pipelines_.Get(shaderId);
VulkanPipeline *iter = pipelines_.Get(pipelineKey);
if (!iter) {
return "";
}
@@ -360,7 +418,62 @@ std::string PipelineManagerVulkan::DebugGetObjectString(std::string id, DebugSha
switch (stringType) {
case SHADER_STRING_SHORT_DESC:
{
return StringFromFormat("%p", iter);
std::stringstream str;
str << topologies[pipelineKey.raster.topology] << " ";
if (pipelineKey.raster.blendEnable) {
str << "Blend(";
str << "C:" << blendOps[pipelineKey.raster.blendOpColor] << "/"
<< blendFactors[pipelineKey.raster.srcColor] << ":" << blendFactors[pipelineKey.raster.destColor] << " ";
if (pipelineKey.raster.blendOpAlpha != VK_BLEND_OP_ADD ||
pipelineKey.raster.srcAlpha != VK_BLEND_FACTOR_ONE ||
pipelineKey.raster.destAlpha != VK_BLEND_FACTOR_ZERO) {
str << "A:" << blendOps[pipelineKey.raster.blendOpAlpha] << "/"
<< blendFactors[pipelineKey.raster.srcColor] << ":" << blendFactors[pipelineKey.raster.destColor] << " ";
}
str << ") ";
}
if (pipelineKey.raster.colorWriteMask != 0xF) {
str << "Mask(";
for (int i = 0; i < 4; i++) {
if (pipelineKey.raster.colorWriteMask & (1 << i)) {
str << "RGBA"[i];
} else {
str << "_";
}
}
str << ") ";
}
if (pipelineKey.raster.depthTestEnable) {
str << "Depth(";
if (pipelineKey.raster.depthWriteEnable)
str << "W, ";
if (pipelineKey.raster.depthCompareOp)
str << compareOps[pipelineKey.raster.depthCompareOp & 7];
str << ") ";
}
if (pipelineKey.raster.stencilTestEnable) {
str << "Stencil(";
str << compareOps[pipelineKey.raster.stencilCompareOp & 7] << " ";
str << stencilOps[pipelineKey.raster.stencilPassOp & 7] << "/";
str << stencilOps[pipelineKey.raster.stencilFailOp & 7] << "/";
str << stencilOps[pipelineKey.raster.stencilDepthFailOp& 7];
str << ") ";
}
if (pipelineKey.raster.logicOpEnable) {
str << "Logic(";
str << ") ";
}
if (pipelineKey.useHWTransform) {
str << "HWX ";
}
if (pipelineKey.vtxDecId) {
str << "V(";
str << StringFromFormat("%08x", pipelineKey.vtxDecId); // TODO: Format nicer.
str << ") ";
} else {
str << "SWX ";
}
return StringFromFormat("%p: %s", iter, str.str().c_str());
}
case SHADER_STRING_SOURCE_CODE:
@@ -385,4 +498,4 @@ void PipelineManagerVulkan::SetLineWidth(float lineWidth) {
pipelines_.Remove(key);
}
});
}
}
+3 -3
View File
@@ -40,10 +40,10 @@ enum class PspAttributeLocation {
struct VulkanPipelineKey {
VulkanPipelineRasterStateKey raster; // prim is included here
VkRenderPass renderPass;
bool useHWTransform;
const VertexDecoder *vtxDec;
VkShaderModule vShader;
VkShaderModule fShader;
uint32_t vtxDecId;
bool useHWTransform;
void ToString(std::string *str) const {
str->resize(sizeof(*this));
@@ -77,7 +77,7 @@ public:
PipelineManagerVulkan(VulkanContext *ctx);
~PipelineManagerVulkan();
VulkanPipeline *GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const VertexDecoder *vtxDec, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform);
VulkanPipeline *GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform);
int GetNumPipelines() const { return (int)pipelines_.size(); }
void Clear();
+4 -1
View File
@@ -28,6 +28,7 @@
#include "util/text/utf8.h"
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanMemory.h"
#include "Common/Log.h"
#include "Common/Common.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
@@ -202,7 +203,7 @@ void ShaderManagerVulkan::DirtyShader() {
DirtyLastShader();
}
void ShaderManagerVulkan::DirtyLastShader() { // disables vertex arrays
void ShaderManagerVulkan::DirtyLastShader() {
lastVShader_ = nullptr;
lastFShader_ = nullptr;
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE);
@@ -243,6 +244,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {
*vshader = lastVShader_;
*fshader = lastFShader_;
_dbg_assert_msg_(G3D, (*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was cached");
// Already all set, no need to look up in shader maps.
return;
}
@@ -272,6 +274,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
*vshader = vs;
*fshader = fs;
_dbg_assert_msg_(G3D, (*vshader)->UseHWTransform() == useHWTransform, "Bad vshader was computed");
}
std::vector<std::string> ShaderManagerVulkan::DebugGetShaderIDs(DebugShaderType type) {
+3 -1
View File
@@ -672,7 +672,9 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
int size = stride * mipHeight;
uint32_t bufferOffset;
VkBuffer texBuf;
void *data = drawEngine_->GetPushBufferForTextureData()->Push(size, &bufferOffset, &texBuf);
// nvidia returns 1 but that can't be healthy... let's align by 16 as a minimum.
int pushAlignment = std::max(16, (int)vulkan_->GetPhysicalDeviceProperties().limits.optimalBufferCopyOffsetAlignment);
void *data = drawEngine_->GetPushBufferForTextureData()->PushAligned(size, &bufferOffset, &texBuf, pushAlignment);
if (replaced.Valid()) {
replaced.Load(i, data, stride);
} else {
+8 -3
View File
@@ -399,7 +399,9 @@ void SystemInfoScreen::CreateViews() {
deviceSpecs->Add(new ItemHeader("OS Information"));
deviceSpecs->Add(new InfoItem("Memory Page Size", StringFromFormat("%d bytes", GetMemoryProtectPageSize())));
deviceSpecs->Add(new InfoItem("RW/RX exclusive: ", PlatformIsWXExclusive() ? "Yes" : "No"));
#ifdef ANDROID
deviceSpecs->Add(new InfoItem("Sustained perf mode: ", System_GetPropertyBool(SYSPROP_SUPPORTS_SUSTAINED_PERF_MODE) ? "Yes" : "No"));
#endif
const char *build = "Release";
#ifdef _DEBUG
@@ -899,14 +901,17 @@ UI::EventReturn JitCompareScreen::OnCurrentBlock(UI::EventParams &e) {
return UI::EVENT_DONE;
}
void ShaderListScreen::ListShaders(DebugShaderType shaderType, UI::LinearLayout *view) {
int ShaderListScreen::ListShaders(DebugShaderType shaderType, UI::LinearLayout *view) {
using namespace UI;
std::vector<std::string> shaderIds_ = gpu->DebugGetShaderIDs(shaderType);
int count = 0;
for (auto id : shaderIds_) {
Choice *choice = view->Add(new Choice(gpu->DebugGetShaderString(id, shaderType, SHADER_STRING_SHORT_DESC)));
choice->SetTag(id);
choice->OnClick.Handle(this, &ShaderListScreen::OnShaderClick);
count++;
}
return count;
}
struct { DebugShaderType type; const char *name; } shaderTypes[] = {
@@ -933,9 +938,9 @@ void ShaderListScreen::CreateViews() {
for (size_t i = 0; i < ARRAY_SIZE(shaderTypes); i++) {
ScrollView *scroll = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0));
LinearLayout *shaderList = new LinearLayout(ORIENT_VERTICAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
ListShaders(shaderTypes[i].type, shaderList);
int count = ListShaders(shaderTypes[i].type, shaderList);
scroll->Add(shaderList);
tabs_->AddTab(shaderTypes[i].name, scroll);
tabs_->AddTab(StringFromFormat("%s (%d)", shaderTypes[i].name, count), scroll);
}
}
+1 -1
View File
@@ -152,7 +152,7 @@ public:
void CreateViews() override;
private:
void ListShaders(DebugShaderType shaderType, UI::LinearLayout *view);
int ListShaders(DebugShaderType shaderType, UI::LinearLayout *view);
UI::EventReturn OnShaderClick(UI::EventParams &e);
+4 -2
View File
@@ -79,7 +79,7 @@
#endif
#ifndef MOBILE_DEVICE
AVIDump avi;
static AVIDump avi;
#endif
static bool frameStep_;
@@ -320,6 +320,7 @@ void EmuScreen::sendMessage(const char *message, const char *value) {
// We will push MainScreen in update().
PSP_Shutdown();
bootPending_ = false;
stopRender_ = true;
invalid_ = true;
host->UpdateDisassembly();
} else if (!strcmp(message, "reset")) {
@@ -331,6 +332,7 @@ void EmuScreen::sendMessage(const char *message, const char *value) {
std::string resetError;
if (!PSP_InitStart(PSP_CoreParameter(), &resetError)) {
ELOG("Error resetting: %s", resetError.c_str());
stopRender_ = true;
screenManager()->switchScreen(new MainScreen());
System_SendMessage("event", "failstartgame");
return;
@@ -1019,7 +1021,7 @@ void EmuScreen::postRender() {
Draw::DrawContext *draw = screenManager()->getDrawContext();
if (!draw)
return;
if (invalid_)
if (stopRender_)
draw->WipeQueue();
draw->EndFrame();
}
+1
View File
@@ -77,6 +77,7 @@ private:
// Something invalid was loaded, don't try to emulate
bool invalid_;
bool quit_;
bool stopRender_ = false;
std::string errorMessage_;
// If set, pauses at the end of the frame.
+1
View File
@@ -807,6 +807,7 @@ void GameSettingsScreen::CreateViews() {
systemSettings->Add(new CheckBox(&g_Config.bDumpFrames, sy->T("Record Display")));
systemSettings->Add(new CheckBox(&g_Config.bUseFFV1, sy->T("Use Lossless Video Codec (FFV1)")));
systemSettings->Add(new CheckBox(&g_Config.bDumpAudio, sy->T("Record Audio")));
systemSettings->Add(new CheckBox(&g_Config.bSaveLoadResetsAVdumping, sy->T("Reset Recording on Save/Load State")));
#endif
if (!g_Config.bSimpleUI) {
systemSettings->Add(new CheckBox(&g_Config.bDayLightSavings, sy->T("Day Light Saving")));
+5 -3
View File
@@ -11,7 +11,7 @@
#define VLOG(...)
#endif
// TODO: Using a thread here is unfinished and does not work correctly.
// This works great. Not much reason to disable so let's not even bother with an option.
const bool useThread = true;
#ifndef UINT64_MAX
@@ -227,6 +227,9 @@ void VulkanRenderManager::StopThread() {
Crash();
}
frameData.readyForRun = false;
for (size_t i = 0; i < frameData.steps.size(); i++) {
delete frameData.steps[i];
}
frameData.steps.clear();
std::unique_lock<std::mutex> lock(frameData.push_mutex);
@@ -803,8 +806,7 @@ void VulkanRenderManager::EndSubmitFrame(int frame) {
present.waitSemaphoreCount = 1;
VkResult res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present);
// TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
// return codes
// TODO: Deal with VK_SUBOPTIMAL_WSI ?
if (res == VK_ERROR_OUT_OF_DATE_KHR) {
// ignore, it'll be fine. this happens sometimes during resizes, and we do make sure to recreate the swap chain.
} else {