mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-25 03:09:13 +01:00
Merge pull request #12968 from hrydgard/dirty-from-drawengine
Dirty state from each DrawEngine
This commit is contained in:
21 files changed
+158
-57
No files matched your search
@@ -450,13 +450,13 @@ void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) {
|
||||
|
||||
// Wipe some pointers
|
||||
if (currentRenderVfb_ == v)
|
||||
currentRenderVfb_ = 0;
|
||||
currentRenderVfb_ = nullptr;
|
||||
if (displayFramebuf_ == v)
|
||||
displayFramebuf_ = 0;
|
||||
displayFramebuf_ = nullptr;
|
||||
if (prevDisplayFramebuf_ == v)
|
||||
prevDisplayFramebuf_ = 0;
|
||||
prevDisplayFramebuf_ = nullptr;
|
||||
if (prevPrevDisplayFramebuf_ == v)
|
||||
prevPrevDisplayFramebuf_ = 0;
|
||||
prevPrevDisplayFramebuf_ = nullptr;
|
||||
|
||||
delete v;
|
||||
}
|
||||
@@ -471,7 +471,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer
|
||||
|
||||
textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED);
|
||||
|
||||
// ugly...
|
||||
// Ugly...
|
||||
if (gstate_c.curRTWidth != vfb->width || gstate_c.curRTHeight != vfb->height) {
|
||||
gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE);
|
||||
}
|
||||
@@ -537,8 +537,6 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe
|
||||
// Wait, can we even do this? Seems highly unsafe.. TODO: Remove
|
||||
if (vfb->last_frame_render != gpuStats.numFlips) {
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "FramebufferSwitch");
|
||||
// GLES resets the blend state on clears.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
} else {
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "FramebufferSwitch");
|
||||
}
|
||||
@@ -549,8 +547,6 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe
|
||||
// This should only happen very briefly when toggling useBufferedRendering_.
|
||||
ResizeFramebufFBO(vfb, vfb->width, vfb->height, true);
|
||||
}
|
||||
// GLES resets the blend state on clears. Since we switched target, we also need to redo viewportscissorstate.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
} else {
|
||||
if (vfb->fbo) {
|
||||
// This should only happen very briefly when toggling useBufferedRendering_.
|
||||
@@ -568,7 +564,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe
|
||||
}
|
||||
textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_UPDATED);
|
||||
|
||||
// ugly...
|
||||
// ugly... is all this needed?
|
||||
if (gstate_c.curRTWidth != vfb->width || gstate_c.curRTHeight != vfb->height) {
|
||||
gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE);
|
||||
}
|
||||
@@ -841,7 +837,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
||||
if (useBufferedRendering_) {
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput");
|
||||
}
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -899,7 +895,6 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
||||
// The game is displaying something directly from RAM. In GTA, it's decoded video.
|
||||
if (!vfb) {
|
||||
DrawFramebufferToOutput(Memory::GetPointer(fbaddr), displayFormat_, displayStride_);
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -909,8 +904,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
|
||||
// Bind and clear the backbuffer. This should be the first time during the frame that it's bound.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "CopyDisplayToOutput_NoFBO");
|
||||
}
|
||||
// GLES resets the blend state on clears.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1068,8 +1062,6 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
|
||||
INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %d x %d x %d", vfb->fb_address, w, h, vfb->format);
|
||||
if (vfb->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO");
|
||||
// GLES resets the blend state on clears.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
if (!skipCopy) {
|
||||
BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min((u16)oldWidth, std::min(vfb->bufferWidth, vfb->width)), std::min((u16)oldHeight, std::min(vfb->height, vfb->bufferHeight)), 0);
|
||||
}
|
||||
@@ -1080,8 +1072,6 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
|
||||
}
|
||||
} else {
|
||||
draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO");
|
||||
// GLES resets the blend state on clears.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
}
|
||||
|
||||
if (!vfb->fbo) {
|
||||
@@ -1851,7 +1841,7 @@ bool FramebufferManagerCommon::GetFramebuffer(u32 fb_address, int fb_stride, GEB
|
||||
bool retval = draw_->CopyFramebufferToMemorySync(bound, Draw::FB_COLOR_BIT, 0, 0, w, h, Draw::DataFormat::R8G8B8A8_UNORM, buffer.GetData(), w, "GetFramebuffer");
|
||||
gpuStats.numReadbacks++;
|
||||
// After a readback we'll have flushed and started over, need to dirty a bunch of things to be safe.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
// We may have blitted to a temp FBO.
|
||||
RebindFramebuffer();
|
||||
return retval;
|
||||
@@ -1886,7 +1876,7 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32
|
||||
// No need to free on failure, that's the caller's job (it likely will reuse a buffer.)
|
||||
bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w, "GetDepthBuffer");
|
||||
// After a readback we'll have flushed and started over, need to dirty a bunch of things to be safe.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);
|
||||
// That may have unbound the framebuffer, rebind to avoid crashes when debugging.
|
||||
RebindFramebuffer();
|
||||
return retval;
|
||||
@@ -1977,9 +1967,6 @@ void FramebufferManagerCommon::PackFramebufferSync_(VirtualFramebuffer *vfb, int
|
||||
ERROR_LOG(G3D, "PackFramebufferSync_: Tried to readback to bad address %08x (stride = %d)", fb_address + dstByteOffset, vfb->fb_stride);
|
||||
}
|
||||
|
||||
// A new command buffer will begin after CopyFrameBufferToMemorySync, so we need to trigger
|
||||
// updates of any dynamic command buffer state by dirtying some stuff.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE);
|
||||
gpuStats.numReadbacks++;
|
||||
}
|
||||
|
||||
@@ -2062,7 +2049,6 @@ void FramebufferManagerCommon::RebindFramebuffer() {
|
||||
// Should this even happen? It could while debugging, but maybe we can just skip binding at all.
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad");
|
||||
}
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
}
|
||||
|
||||
std::vector<FramebufferInfo> FramebufferManagerCommon::GetFramebufferList() {
|
||||
|
||||
@@ -307,6 +307,8 @@ void DrawEngineD3D11::BeginFrame() {
|
||||
NOTICE_LOG(G3D, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
lastRenderStepId_ = -1;
|
||||
}
|
||||
|
||||
VertexArrayInfoD3D11::~VertexArrayInfoD3D11() {
|
||||
@@ -325,6 +327,14 @@ void DrawEngineD3D11::DoFlush() {
|
||||
gpuStats.numFlushes++;
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
|
||||
int curRenderStepId = draw_->GetCurrentStepId();
|
||||
if (lastRenderStepId_ != curRenderStepId) {
|
||||
// Dirty everything that has dynamic state that will need re-recording.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
lastRenderStepId_ = curRenderStepId;
|
||||
}
|
||||
|
||||
// This is not done on every drawcall, we collect vertex data
|
||||
// until critical state changes. That's when we draw (flush).
|
||||
|
||||
|
||||
@@ -216,4 +216,6 @@ private:
|
||||
|
||||
// Hardware tessellation
|
||||
TessellationDataTransferD3D11 *tessDataTransferD3D11;
|
||||
|
||||
int lastRenderStepId_ = -1;
|
||||
};
|
||||
@@ -83,7 +83,7 @@ static const D3DVERTEXELEMENT9 TransformedVertexElements[] = {
|
||||
D3DDECL_END()
|
||||
};
|
||||
|
||||
DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : vai_(256), vertexDeclMap_(64) {
|
||||
DrawEngineDX9::DrawEngineDX9(Draw::DrawContext *draw) : draw_(draw), vai_(256), vertexDeclMap_(64) {
|
||||
device_ = (LPDIRECT3DDEVICE9)draw->GetNativeObject(Draw::NativeObject::DEVICE);
|
||||
decOptions_.expandAllWeightsToFloat = true;
|
||||
decOptions_.expand8BitNormalsToFloat = true;
|
||||
@@ -299,14 +299,27 @@ static uint32_t SwapRB(uint32_t c) {
|
||||
return (c & 0xFF00FF00) | ((c >> 16) & 0xFF) | ((c << 16) & 0xFF0000);
|
||||
}
|
||||
|
||||
void DrawEngineDX9::BeginFrame() {
|
||||
DecimateTrackedVertexArrays();
|
||||
|
||||
lastRenderStepId_ = -1;
|
||||
}
|
||||
|
||||
// The inline wrapper in the header checks for numDrawCalls == 0
|
||||
void DrawEngineDX9::DoFlush() {
|
||||
gpuStats.numFlushes++;
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
|
||||
int curRenderStepId = draw_->GetCurrentStepId();
|
||||
if (lastRenderStepId_ != curRenderStepId) {
|
||||
// Dirty everything that has dynamic state that will need re-recording.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
lastRenderStepId_ = curRenderStepId;
|
||||
}
|
||||
|
||||
// This is not done on every drawcall, we should collect vertex data
|
||||
// until critical state changes. That's when we draw (flush).
|
||||
|
||||
GEPrimitiveType prim = prevPrim_;
|
||||
ApplyDrawState(prim);
|
||||
|
||||
|
||||
@@ -123,7 +123,8 @@ public:
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
void ClearTrackedVertexArrays() override;
|
||||
void DecimateTrackedVertexArrays();
|
||||
|
||||
void BeginFrame();
|
||||
|
||||
// So that this can be inlined
|
||||
void Flush() {
|
||||
@@ -143,6 +144,7 @@ public:
|
||||
protected:
|
||||
// Not currently supported.
|
||||
bool UpdateUseHWTessellation(bool enable) override { return false; }
|
||||
void DecimateTrackedVertexArrays();
|
||||
|
||||
private:
|
||||
void DoFlush();
|
||||
@@ -156,6 +158,7 @@ private:
|
||||
void MarkUnreliable(VertexArrayInfoDX9 *vai);
|
||||
|
||||
LPDIRECT3DDEVICE9 device_ = nullptr;
|
||||
Draw::DrawContext *draw_;
|
||||
|
||||
PrehashMap<VertexArrayInfoDX9 *, nullptr> vai_;
|
||||
DenseHashMap<u32, IDirect3DVertexDeclaration9 *, nullptr> vertexDeclMap_;
|
||||
@@ -170,6 +173,8 @@ private:
|
||||
|
||||
// Hardware tessellation
|
||||
TessellationDataTransferDX9 *tessDataTransferDX9;
|
||||
|
||||
int lastRenderStepId_ = -1;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -282,7 +282,7 @@ void GPU_DX9::ReapplyGfxState() {
|
||||
|
||||
void GPU_DX9::BeginFrame() {
|
||||
textureCacheDX9_->StartFrame();
|
||||
drawEngine_.DecimateTrackedVertexArrays();
|
||||
drawEngine_.BeginFrame();
|
||||
depalShaderCache_.Decimate();
|
||||
// fragmentTestCache_.Decimate();
|
||||
|
||||
|
||||
@@ -156,9 +156,13 @@ void DrawEngineGLES::ClearInputLayoutMap() {
|
||||
}
|
||||
|
||||
void DrawEngineGLES::BeginFrame() {
|
||||
DecimateTrackedVertexArrays();
|
||||
|
||||
FrameData &frameData = frameData_[render_->GetCurFrame()];
|
||||
render_->BeginPushBuffer(frameData.pushIndex);
|
||||
render_->BeginPushBuffer(frameData.pushVertex);
|
||||
|
||||
lastRenderStepId_ = -1;
|
||||
}
|
||||
|
||||
void DrawEngineGLES::EndFrame() {
|
||||
@@ -305,6 +309,15 @@ void DrawEngineGLES::DoFlush() {
|
||||
gpuStats.numFlushes++;
|
||||
gpuStats.numTrackedVertexArrays = (int)vai_.size();
|
||||
|
||||
// A new render step means we need to flush any dynamic state. Really, any state that is reset in
|
||||
// GLQueueRunner::PerformRenderPass.
|
||||
int curRenderStepId = render_->GetCurrentStepId();
|
||||
if (lastRenderStepId_ != curRenderStepId) {
|
||||
// Dirty everything that has dynamic state that will need re-recording.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE);
|
||||
lastRenderStepId_ = curRenderStepId;
|
||||
}
|
||||
|
||||
bool textureNeedsApply = false;
|
||||
if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {
|
||||
textureCache_->SetTexture();
|
||||
|
||||
@@ -150,7 +150,6 @@ public:
|
||||
void DeviceRestore(Draw::DrawContext *draw);
|
||||
|
||||
void ClearTrackedVertexArrays() override;
|
||||
void DecimateTrackedVertexArrays();
|
||||
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
@@ -186,6 +185,7 @@ public:
|
||||
|
||||
protected:
|
||||
bool UpdateUseHWTessellation(bool enable) override;
|
||||
void DecimateTrackedVertexArrays();
|
||||
|
||||
private:
|
||||
void InitDeviceObjects();
|
||||
@@ -229,6 +229,8 @@ private:
|
||||
|
||||
int bufferDecimationCounter_ = 0;
|
||||
|
||||
int lastRenderStepId_ = -1;
|
||||
|
||||
// Hardware tessellation
|
||||
TessellationDataTransferGLES *tessDataTransferGLES;
|
||||
};
|
||||
@@ -373,7 +373,6 @@ void GPU_GLES::ReapplyGfxState() {
|
||||
|
||||
void GPU_GLES::BeginFrame() {
|
||||
textureCacheGL_->StartFrame();
|
||||
drawEngine_.DecimateTrackedVertexArrays();
|
||||
depalShaderCache_.Decimate();
|
||||
fragmentTestCache_.Decimate();
|
||||
|
||||
|
||||
@@ -320,8 +320,8 @@ void DrawEngineGLES::ApplyDrawState(int prim) {
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineGLES::ApplyDrawStateLate(bool setStencil, int stencilValue) {
|
||||
if (setStencil) {
|
||||
void DrawEngineGLES::ApplyDrawStateLate(bool setStencilValue, int stencilValue) {
|
||||
if (setStencilValue) {
|
||||
render_->SetStencilFunc(GL_TRUE, GL_ALWAYS, stencilValue, 255);
|
||||
}
|
||||
|
||||
|
||||
@@ -259,9 +259,10 @@ void DrawEngineVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *d
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::BeginFrame() {
|
||||
// Too many issues right now to allow reuse.
|
||||
lastPipeline_ = nullptr;
|
||||
|
||||
lastRenderStepId_ = -1;
|
||||
|
||||
int curFrame = vulkan_->GetCurFrame();
|
||||
FrameData *frame = &frame_[curFrame];
|
||||
|
||||
@@ -587,10 +588,16 @@ void DrawEngineVulkan::DoFlush() {
|
||||
|
||||
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
|
||||
// HACK: These two lines should only execute if we started on a new render pass. Can't tell from in here though...
|
||||
// TODO: Move this into the below if statement. Little scary change though so holding off until 1.11.
|
||||
lastPipeline_ = nullptr;
|
||||
|
||||
// Since we have a new cmdbuf, dirty our dynamic state so it gets re-set.
|
||||
// gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE|DIRTY_DEPTHSTENCIL_STATE|DIRTY_BLEND_STATE);
|
||||
int curRenderStepId = renderManager->GetCurrentStepId();
|
||||
if (lastRenderStepId_ != curRenderStepId) {
|
||||
// Dirty everything that has dynamic state that will need re-recording.
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE);
|
||||
lastRenderStepId_ = curRenderStepId;
|
||||
}
|
||||
|
||||
FrameData *frame = &frame_[vulkan_->GetCurFrame()];
|
||||
|
||||
|
||||
@@ -302,4 +302,6 @@ private:
|
||||
|
||||
// Hardware tessellation
|
||||
TessellationDataTransferVulkan *tessDataTransferVulkan;
|
||||
|
||||
int lastRenderStepId_ = -1;
|
||||
};
|
||||
@@ -796,7 +796,6 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
}
|
||||
if (c.clear.colorMask != colorMask) {
|
||||
glColorMask(c.clear.colorMask & 1, (c.clear.colorMask >> 1) & 1, (c.clear.colorMask >> 2) & 1, (c.clear.colorMask >> 3) & 1);
|
||||
colorMask = c.clear.colorMask;
|
||||
}
|
||||
if (c.clear.clearMask & GL_COLOR_BUFFER_BIT) {
|
||||
float color[4];
|
||||
@@ -818,6 +817,10 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
|
||||
glClearStencil(c.clear.clearStencil);
|
||||
}
|
||||
glClear(c.clear.clearMask);
|
||||
// Restore the color mask if it was different.
|
||||
if (c.clear.colorMask != colorMask) {
|
||||
glColorMask(colorMask & 1, (colorMask >> 1) & 1, (colorMask >> 2) & 1, (colorMask >> 3) & 1);
|
||||
}
|
||||
if (c.clear.scissorW == 0) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "thin3d/thin3d.h"
|
||||
#include "thread/threadutil.h"
|
||||
#include "base/logging.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "Common/MemoryUtil.h"
|
||||
|
||||
#if 0 // def _DEBUG
|
||||
@@ -318,9 +317,6 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende
|
||||
step->dependencies.insert(fb);
|
||||
}
|
||||
}
|
||||
|
||||
// Every step clears this state.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE);
|
||||
}
|
||||
|
||||
void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment) {
|
||||
@@ -346,9 +342,6 @@ void GLRenderManager::CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLR
|
||||
if (dstPos.x != 0 || dstPos.y != 0 || !fillsDst)
|
||||
step->dependencies.insert(dst);
|
||||
steps_.push_back(step);
|
||||
|
||||
// Every step clears this state.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE);
|
||||
}
|
||||
|
||||
void GLRenderManager::BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLRect2D dstRect, int aspectMask, bool filter, const char *tag) {
|
||||
@@ -365,9 +358,6 @@ void GLRenderManager::BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLR
|
||||
if (!fillsDst)
|
||||
step->dependencies.insert(dst);
|
||||
steps_.push_back(step);
|
||||
|
||||
// Every step clears this state.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE);
|
||||
}
|
||||
|
||||
bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) {
|
||||
@@ -382,9 +372,6 @@ bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspec
|
||||
step->tag = tag;
|
||||
steps_.push_back(step);
|
||||
|
||||
// Every step clears this state.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE);
|
||||
|
||||
curRenderStep_ = nullptr;
|
||||
FlushSync();
|
||||
|
||||
@@ -414,9 +401,6 @@ void GLRenderManager::CopyImageToMemorySync(GLRTexture *texture, int mipLevel, i
|
||||
step->tag = tag;
|
||||
steps_.push_back(step);
|
||||
|
||||
// Every step clears this state.
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE);
|
||||
|
||||
curRenderStep_ = nullptr;
|
||||
FlushSync();
|
||||
|
||||
|
||||
@@ -501,8 +501,25 @@ public:
|
||||
pushbuffer->End();
|
||||
}
|
||||
|
||||
// This starts a new step (like a "render pass" in Vulkan).
|
||||
//
|
||||
// After a "CopyFramebuffer" or the other functions that start "steps", you need to call this beforce
|
||||
// making any new render state changes or draw calls.
|
||||
//
|
||||
// The following state needs to be reset by the caller after calling this (and will thus not safely carry over from
|
||||
// the previous one):
|
||||
// * Viewport/Scissor
|
||||
// * Depth/stencil
|
||||
// * Blend
|
||||
// * Raster state like primitive, culling, etc.
|
||||
//
|
||||
// It can be useful to use GetCurrentStepId() to figure out when you need to send all this state again, if you're
|
||||
// not keeping track of your calls to this function on your own.
|
||||
void BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRenderPassAction color, GLRRenderPassAction depth, GLRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag);
|
||||
|
||||
// Binds a framebuffer as a texture, for the following draws.
|
||||
void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit, int attachment);
|
||||
|
||||
bool CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag);
|
||||
void CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag);
|
||||
|
||||
@@ -812,7 +829,7 @@ public:
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
// If scissorW == 0, no scissor is applied.
|
||||
// If scissorW == 0, no scissor is applied (the whole render target is cleared).
|
||||
void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask, int colorMask, int scissorX, int scissorY, int scissorW, int scissorH) {
|
||||
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
|
||||
if (!clearMask)
|
||||
@@ -920,6 +937,12 @@ public:
|
||||
skipGLCalls_ = true;
|
||||
}
|
||||
|
||||
// Gets a frame-unique ID of the current step being recorded. Can be used to figure out
|
||||
// when the current step has changed, which means the caller will need to re-record its state.
|
||||
int GetCurrentStepId() const {
|
||||
return (int)steps_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
void BeginSubmitFrame(int frame);
|
||||
void EndSubmitFrame(int frame);
|
||||
|
||||
@@ -105,8 +105,27 @@ public:
|
||||
// Zaps queued up commands. Use if you know there's a risk you've queued up stuff that has already been deleted. Can happen during in-game shutdown.
|
||||
void Wipe();
|
||||
|
||||
// This starts a new step containing a render pass.
|
||||
//
|
||||
// After a "CopyFramebuffer" or the other functions that start "steps", you need to call this beforce
|
||||
// making any new render state changes or draw calls.
|
||||
//
|
||||
// The following dynamic state needs to be reset by the caller after calling this (and will thus not safely carry over from
|
||||
// the previous one):
|
||||
// * Viewport/Scissor
|
||||
// * Stencil parameters
|
||||
// * Blend color
|
||||
//
|
||||
// (Most other state is directly decided by your choice of pipeline and descriptor set, so not handled here).
|
||||
//
|
||||
// It can be useful to use GetCurrentStepId() to figure out when you need to send all this state again, if you're
|
||||
// not keeping track of your calls to this function on your own.
|
||||
void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, VKRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag);
|
||||
|
||||
// Returns an ImageView corresponding to a framebuffer. Is called BindFramebufferAsTexture to maintain a similar interface
|
||||
// as the other backends, even though there's no actual binding happening here.
|
||||
VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment);
|
||||
|
||||
bool CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag);
|
||||
void CopyImageToMemorySync(VkImage image, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag);
|
||||
|
||||
@@ -232,6 +251,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Gets a frame-unique ID of the current step being recorded. Can be used to figure out
|
||||
// when the current step has changed, which means the caller will need to re-record its state.
|
||||
int GetCurrentStepId() const {
|
||||
return (int)steps_.size();
|
||||
}
|
||||
|
||||
void CreateBackbuffers();
|
||||
void DestroyBackbuffers();
|
||||
|
||||
|
||||
@@ -673,6 +673,8 @@ public:
|
||||
// Flush state like scissors etc so the caller can do its own custom drawing.
|
||||
virtual void FlushState() {}
|
||||
|
||||
virtual int GetCurrentStepId() const = 0;
|
||||
|
||||
protected:
|
||||
ShaderModule *vsPresets_[VS_MAX_PRESET];
|
||||
ShaderModule *fsPresets_[FS_MAX_PRESET];
|
||||
|
||||
@@ -158,6 +158,10 @@ public:
|
||||
|
||||
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
|
||||
|
||||
int GetCurrentStepId() const override {
|
||||
return stepId_;
|
||||
}
|
||||
|
||||
private:
|
||||
void ApplyCurrentState();
|
||||
|
||||
@@ -166,6 +170,7 @@ private:
|
||||
ID3D11DeviceContext *context_;
|
||||
ID3D11Device1 *device1_;
|
||||
ID3D11DeviceContext1 *context1_;
|
||||
int stepId_ = -1;
|
||||
|
||||
ID3D11Texture2D *bbRenderTargetTex_ = nullptr; // NOT OWNED
|
||||
ID3D11RenderTargetView *bbRenderTargetView_ = nullptr;
|
||||
@@ -353,6 +358,7 @@ void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param1
|
||||
// Make sure that we don't eliminate the next time the render target is set.
|
||||
curRenderTargetView_ = nullptr;
|
||||
curDepthStencilView_ = nullptr;
|
||||
stepId_ = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1394,11 +1400,13 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x
|
||||
D3D11_BOX srcBox{ (UINT)x, (UINT)y, (UINT)z, (UINT)(x + width), (UINT)(y + height), (UINT)(z + depth) };
|
||||
context_->CopySubresourceRegion(dstTex, dstLevel, dstX, dstY, dstZ, srcTex, level, &srcBox);
|
||||
}
|
||||
stepId_++;
|
||||
}
|
||||
|
||||
bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) {
|
||||
// Unfortunately D3D11 has no equivalent to this, gotta render a quad. Well, in some cases we can issue a copy instead.
|
||||
Crash();
|
||||
stepId_++;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1519,6 +1527,7 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel
|
||||
if (!useGlobalPacktex) {
|
||||
packTex->Release();
|
||||
}
|
||||
stepId_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1562,6 +1571,8 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren
|
||||
if (mask && curDepthStencilView_) {
|
||||
context_->ClearDepthStencilView(curDepthStencilView_, mask, rp.clearDepth, rp.clearStencil);
|
||||
}
|
||||
|
||||
stepId_++;
|
||||
}
|
||||
|
||||
// color must be 0, for now.
|
||||
|
||||
@@ -599,11 +599,16 @@ public:
|
||||
|
||||
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
|
||||
|
||||
int GetCurrentStepId() const override {
|
||||
return stepId_;
|
||||
}
|
||||
|
||||
private:
|
||||
LPDIRECT3D9 d3d_;
|
||||
LPDIRECT3D9EX d3dEx_;
|
||||
LPDIRECT3DDEVICE9 device_;
|
||||
LPDIRECT3DDEVICE9EX deviceEx_;
|
||||
int stepId_ = -1;
|
||||
int adapterId_ = -1;
|
||||
D3DADAPTER_IDENTIFIER9 identifier_{};
|
||||
D3DCAPS9 d3dCaps_;
|
||||
@@ -1160,6 +1165,7 @@ void D3D9Context::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPa
|
||||
|
||||
dxstate.scissorRect.restore();
|
||||
dxstate.viewport.restore();
|
||||
stepId_++;
|
||||
}
|
||||
|
||||
uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) {
|
||||
@@ -1187,10 +1193,6 @@ uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit
|
||||
}
|
||||
}
|
||||
|
||||
LPDIRECT3DSURFACE9 fbo_get_color_for_read(D3D9Framebuffer *fbo) {
|
||||
return fbo->surf;
|
||||
}
|
||||
|
||||
void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int color) {
|
||||
D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo;
|
||||
switch (channelBit) {
|
||||
@@ -1228,6 +1230,7 @@ bool D3D9Context::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int
|
||||
RECT dstRect{ (LONG)dstX1, (LONG)dstY1, (LONG)dstX2, (LONG)dstY2 };
|
||||
LPDIRECT3DSURFACE9 srcSurf = src ? src->surf : deviceRTsurf;
|
||||
LPDIRECT3DSURFACE9 dstSurf = dst ? dst->surf : deviceRTsurf;
|
||||
stepId_++;
|
||||
return SUCCEEDED(device_->StretchRect(srcSurf, &srcRect, dstSurf, &dstRect, filter == FB_BLIT_LINEAR ? D3DTEXF_LINEAR : D3DTEXF_POINT));
|
||||
}
|
||||
|
||||
@@ -1245,6 +1248,9 @@ void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, voi
|
||||
device_->GetRenderTarget(0, &deviceRTsurf);
|
||||
device_->GetDepthStencilSurface(&deviceDSsurf);
|
||||
break;
|
||||
case Event::PRESENTED:
|
||||
stepId_ = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -478,6 +478,10 @@ public:
|
||||
|
||||
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override {}
|
||||
|
||||
int GetCurrentStepId() const {
|
||||
return renderManager_.GetCurrentStepId();
|
||||
}
|
||||
|
||||
private:
|
||||
void ApplySamplers();
|
||||
|
||||
|
||||
@@ -482,6 +482,10 @@ public:
|
||||
|
||||
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
|
||||
|
||||
int GetCurrentStepId() const {
|
||||
return renderManager_.GetCurrentStepId();
|
||||
}
|
||||
|
||||
private:
|
||||
VulkanTexture *GetNullTexture();
|
||||
VulkanContext *vulkan_ = nullptr;
|
||||
|
||||
Reference in new issue
Block a user