Skip to content

Commit

Permalink
Unify CopyDisplayToOutput
Browse files Browse the repository at this point in the history
  • Loading branch information
hrydgard committed Feb 15, 2017
1 parent 23762ef commit 68c5a6c
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 758 deletions.
217 changes: 217 additions & 0 deletions GPU/Common/FramebufferCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,223 @@ void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *v
}
}

void FramebufferManagerCommon::CopyDisplayToOutput() {
DownloadFramebufferOnSwitch(currentRenderVfb_);

SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
draw_->BindBackbufferAsRenderTarget();
currentRenderVfb_ = 0;

if (displayFramebufPtr_ == 0) {
DEBUG_LOG(SCEGE, "Display disabled, displaying only black");
// No framebuffer to display! Clear to black.
ClearBuffer();
return;
}

if (useBufferedRendering_) {
draw_->Clear(Draw::FB_COLOR_BIT | Draw::FB_STENCIL_BIT | Draw::FB_DEPTH_BIT, 0, 0, 0);
}

u32 offsetX = 0;
u32 offsetY = 0;

CardboardSettings cardboardSettings;
GetCardboardSettings(&cardboardSettings);

VirtualFramebuffer *vfb = GetVFBAt(displayFramebufPtr_);
if (!vfb) {
// Let's search for a framebuf within this range.
const u32 addr = (displayFramebufPtr_ & 0x03FFFFFF) | 0x04000000;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *v = vfbs_[i];
const u32 v_addr = (v->fb_address & 0x03FFFFFF) | 0x04000000;
const u32 v_size = FramebufferByteSize(v);
if (addr >= v_addr && addr < v_addr + v_size) {
const u32 dstBpp = v->format == GE_FORMAT_8888 ? 4 : 2;
const u32 v_offsetX = ((addr - v_addr) / dstBpp) % v->fb_stride;
const u32 v_offsetY = ((addr - v_addr) / dstBpp) / v->fb_stride;
// We have enough space there for the display, right?
if (v_offsetX + 480 > (u32)v->fb_stride || v->bufferHeight < v_offsetY + 272) {
continue;
}
// Check for the closest one.
if (offsetY == 0 || offsetY > v_offsetY) {
offsetX = v_offsetX;
offsetY = v_offsetY;
vfb = v;
}
}
}

if (vfb) {
// Okay, we found one above.
INFO_LOG_REPORT_ONCE(displayoffset, HLE, "Rendering from framebuf with offset %08x -> %08x+%dx%d", addr, vfb->fb_address, offsetX, offsetY);
}
}

if (vfb && vfb->format != displayFormat_) {
if (vfb->last_frame_render + FBO_OLD_AGE < gpuStats.numFlips) {
// The game probably switched formats on us.
vfb->format = displayFormat_;
} else {
vfb = 0;
}
}

if (!vfb) {
if (Memory::IsValidAddress(displayFramebufPtr_)) {
// The game is displaying something directly from RAM. In GTA, it's decoded video.

// First check that it's not a known RAM copy of a VRAM framebuffer though, as in MotoGP
for (auto iter = knownFramebufferRAMCopies_.begin(); iter != knownFramebufferRAMCopies_.end(); ++iter) {
if (iter->second == displayFramebufPtr_) {
vfb = GetVFBAt(iter->first);
}
}

if (!vfb) {
// Just a pointer to plain memory to draw. We should create a framebuffer, then draw to it.
DrawFramebufferToOutput(Memory::GetPointer(displayFramebufPtr_), displayFormat_, displayStride_, true);
return;
}
} else {
DEBUG_LOG(SCEGE, "Found no FBO to display! displayFBPtr = %08x", displayFramebufPtr_);
// No framebuffer to display! Clear to black.
ClearBuffer();
return;
}
}

vfb->usageFlags |= FB_USAGE_DISPLAYED_FRAMEBUFFER;
vfb->last_frame_displayed = gpuStats.numFlips;
vfb->dirtyAfterDisplay = false;
vfb->reallyDirtyAfterDisplay = false;

if (prevDisplayFramebuf_ != displayFramebuf_) {
prevPrevDisplayFramebuf_ = prevDisplayFramebuf_;
}
if (displayFramebuf_ != vfb) {
prevDisplayFramebuf_ = displayFramebuf_;
}
displayFramebuf_ = vfb;

if (vfb->fbo) {
DEBUG_LOG(SCEGE, "Displaying FBO %08x", vfb->fb_address);
DisableState();

draw_->BindFramebufferAsTexture(vfb->fbo, 0, Draw::FB_COLOR_BIT, 0);

int uvRotation = (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL;

// Output coordinates
float x, y, w, h;
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, uvRotation);

// TODO ES3: Use glInvalidateFramebuffer to discard depth/stencil data at the end of frame.

float u0 = offsetX / (float)vfb->bufferWidth;
float v0 = offsetY / (float)vfb->bufferHeight;
float u1 = (480.0f + offsetX) / (float)vfb->bufferWidth;
float v1 = (272.0f + offsetY) / (float)vfb->bufferHeight;

if (!usePostShader_) {
bool linearFilter = g_Config.iBufFilter == SCALE_LINEAR;
// We are doing the DrawActiveTexture call directly to the backbuffer here. Hence, we must
// flip V.
Bind2DShader();
if (needBackBufferYSwap_)
std::swap(v0, v1);
if (cardboardSettings.enabled) {
// Left Eye Image
SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, linearFilter);

// Right Eye Image
SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, linearFilter);
} else {
// Fullscreen Image
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, linearFilter);
}
} else if (usePostShader_ && extraFBOs_.size() == 1 && !postShaderAtOutputResolution_) {
// An additional pass, post-processing shader to the extra FBO.
draw_->BindFramebufferAsRenderTarget(extraFBOs_[0]);
int fbo_w, fbo_h;
draw_->GetFramebufferDimensions(extraFBOs_[0], &fbo_w, &fbo_h);
SetViewport2D(0, 0, fbo_w, fbo_h);
shaderManager_->DirtyLastShader(); // dirty lastShader_
PostShaderUniforms uniforms{};
CalculatePostShaderUniforms(vfb->bufferWidth, vfb->bufferHeight, renderWidth_, renderHeight_, &uniforms);
BindPostShader(uniforms);
bool linearFilter = g_Config.iBufFilter == SCALE_LINEAR;
DrawActiveTexture(0, 0, fbo_w, fbo_h, fbo_w, fbo_h, 0.0f, 0.0f, 1.0f, 1.0f, ROTATION_LOCKED_HORIZONTAL, linearFilter);

draw_->BindBackbufferAsRenderTarget();

// Use the extra FBO, with applied post-processing shader, as a texture.
// fbo_bind_as_texture(extraFBOs_[0], FB_COLOR_BIT, 0);
if (extraFBOs_.size() == 0) {
ERROR_LOG(G3D, "WTF?");
return;
}
draw_->BindFramebufferAsTexture(extraFBOs_[0], 0, Draw::FB_COLOR_BIT, 0);

// We are doing the DrawActiveTexture call directly to the backbuffer after here. Hence, we must
// flip V.
if (needBackBufferYSwap_)
std::swap(v0, v1);
Bind2DShader();
linearFilter = !postShaderIsUpscalingFilter_ && g_Config.iBufFilter == SCALE_LINEAR;
if (g_Config.bEnableCardboard) {
// Left Eye Image
SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, linearFilter);

// Right Eye Image
SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, linearFilter);
} else {
// Fullscreen Image
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, linearFilter);
}

/*
if (gl_extensions.GLES3 && glInvalidateFramebuffer != nullptr) {
draw_->BindFramebufferAsRenderTarget(extraFBOs_[0]);
GLenum attachments[3] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT };
glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, attachments);
}*/
} else {
// We are doing the DrawActiveTexture call directly to the backbuffer here. Hence, we must
// flip V.
if (needBackBufferYSwap_)
std::swap(v0, v1);
bool linearFilter = g_Config.iBufFilter == SCALE_LINEAR;

shaderManager_->DirtyLastShader(); // dirty lastShader_ BEFORE drawing
PostShaderUniforms uniforms{};
CalculatePostShaderUniforms(vfb->bufferWidth, vfb->bufferHeight, vfb->renderWidth, vfb->renderHeight, &uniforms);
BindPostShader(uniforms);
if (g_Config.bEnableCardboard) {
// Left Eye Image
SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, linearFilter);

// Right Eye Image
SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, linearFilter);
} else {
// Fullscreen Image
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, linearFilter);
}
}
}
}

void FramebufferManagerCommon::DecimateFBOs() {
if (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) {
draw_->BindBackbufferAsRenderTarget();
Expand Down
4 changes: 3 additions & 1 deletion GPU/Common/FramebufferCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ class FramebufferManagerCommon {
}
virtual void RebindFramebuffer() = 0;

void CopyDisplayToOutput();

bool NotifyFramebufferCopy(u32 src, u32 dest, int size, bool isMemset, u32 skipDrawReason);
void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt);
void UpdateFromMemory(u32 addr, int size, bool safe);
Expand Down Expand Up @@ -265,7 +267,7 @@ class FramebufferManagerCommon {
virtual void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) = 0;
virtual void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, bool linearFilter) = 0;
virtual void Bind2DShader() = 0;
virtual void BindPostShader(const PostShaderUniforms &uniforms) {}
virtual void BindPostShader(const PostShaderUniforms &uniforms) = 0;

// Cardboard Settings Calculator
void GetCardboardSettings(CardboardSettings *cardboardSettings);
Expand Down
Loading

0 comments on commit 68c5a6c

Please sign in to comment.