mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Merge branch 'master' into TemporaryHackishBranch
This commit is contained in:
commit
c7cddb93fa
37 files changed
+409
-921
No files matched your search
+13
-2
@@ -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() {
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ public:
|
||||
bool bUseFFV1;
|
||||
bool bDumpFrames;
|
||||
bool bDumpAudio;
|
||||
bool bSaveLoadResetsAVdumping;
|
||||
bool bEnableLogging;
|
||||
bool bDumpDecryptedEboot;
|
||||
bool bFullscreenOnDoubleclick;
|
||||
|
||||
+24
-3
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
@@ -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());
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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());
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in new issue
Block a user