void RSManager::prePresent(bool doNotFlip) {
	if(dumpingFrame) {
		dumpSurface("framedump_prePresent", backBuffers[0]);
		SDLOG(0, "============================================\nFinished dumping frame.\n");
		Settings::get().restoreLogLevel();
		dumpingFrame = false;
	}

	// downsample offscreen backbuffer to screen
	if(downsampling) {
		storeRenderState();
		d3ddev->BeginScene();
		plugin->preDownsample(backBuffers[0]);
		SDLOG(2, "Scaling fake backbuffer (%p)\n", backBuffers[0]);
		IDirect3DSurface9* realBackBuffer;
		d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &realBackBuffer);
		SDLOG(2, "- to backbuffer %p\n", realBackBuffer);
		scaler->go(backBufferTextures[0], realBackBuffer);
		realBackBuffer->Release();
		SDLOG(2, "- scaling complete!\n");
		d3ddev->EndScene();
		if(takeScreenshot == SCREENSHOT_STANDARD) {
			takeScreenshot = SCREENSHOT_NONE;
			captureRTScreen();
		}
		
		if(swapEffect == SWAP_FLIP && Settings::get().getEmulateFlipBehaviour() && !doNotFlip) {
			d3ddev->StretchRect(backBuffers[0], NULL, extraBuffer->getSurf(), NULL, D3DTEXF_NONE);
			for(unsigned bb=0; bb<numBackBuffers; ++bb) {
				d3ddev->StretchRect(backBuffers[bb+1], NULL, backBuffers[bb], NULL, D3DTEXF_NONE);
			}
			d3ddev->StretchRect(extraBuffer->getSurf(), NULL, backBuffers[numBackBuffers-1], NULL, D3DTEXF_NONE);
			SDLOG(2, "Advanced flip queue\n");
		} else {
			SDLOG(2, "Not \"flipping\" backbuffers\n");
		}
		restoreRenderState();
	}
	else {
		storeRenderState();
		d3ddev->BeginScene();
		IDirect3DSurface9* bb = NULL;
		d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &bb);
		if(dumpingFrame) {
			dumpSurface("framedump_preplugin", bb);
		}
		plugin->preDownsample(bb);
		if(dumpingFrame) {
			dumpSurface("framedump_postplugin", bb);
		}
		SAFERELEASE(bb);
		d3ddev->EndScene();
		restoreRenderState();
	}

	if(takeScreenshot == SCREENSHOT_FULL || takeScreenshot == SCREENSHOT_HUDLESS || (!downsampling && takeScreenshot == SCREENSHOT_STANDARD)) {
		storeRenderState();
		takeScreenshot = SCREENSHOT_NONE;
		if(downsampling) d3ddev->SetRenderTarget(0, backBuffers[0]);
		captureRTScreen("full resolution");
		restoreRenderState();
	}

	// Frame time measurements
	cpuFrameTimes.add(cpuFrameTimer.elapsed() / 1000.0);
	perfMonitor->end();
	frameTimeText->text = format("Frame times (avg/max):\n CPU: %6.2lf / %6.2lf ms\n GPU: %6.2f / %6.2lf ms\nVid mem. avail.: %4u MB", 
		cpuFrameTimes.get(), cpuFrameTimes.maximum(), perfMonitor->getCurrent(), perfMonitor->getMax(), d3ddev->GetAvailableTextureMem()/1024/1024);

	// Draw console
	if(console.needsDrawing()) {
		storeRenderState();
		d3ddev->BeginScene();
		IDirect3DSurface9* realBackBuffer;
		d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &realBackBuffer);
		d3ddev->SetRenderTarget(0, realBackBuffer);
		console.draw();
		realBackBuffer->Release();
		d3ddev->EndScene();
		restoreRenderState();
	}
	
	// reset per-frame vars
	renderTargetSwitches = 0;
	plugin->prePresent();

	//////////////////////////////////////////// IO
	KeyActions::get().processIO();
	//////////////////////////////////////////// IO

	if(dumpingFrame) {
		Settings::get().elevateLogLevel(50);
		SDLOG(0, "============================================\nStarting frame dump.\n");
	}

	SDLOG(2, "Pre-present complete\n");
}
void RSManagerDX9::prePresent(bool doNotFlip) {
	// downsample offscreen backbuffer to screen
	if(downsampling) {
		storeRenderState();
		d3ddev->BeginScene();
		// restore neutral state
		initStateBlock->Apply();
		// apply plugin actions if specified
		plugin->preDownsample(backBuffers[0]->getSurf());

		// actual scaling
		SDLOG(2, "Scaling fake backbuffer (%p)\n", backBuffers[0]);
		IDirect3DSurface9* realBackBuffer;
		d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &realBackBuffer);
		SDLOG(2, "- to backbuffer %p\n", realBackBuffer);
		scaler->go(backBuffers[0]->getTex(), realBackBuffer);
		SDLOG(2, "- scaling complete!\n");
		// apply plugin actions if specified
		plugin->postDownsample(realBackBuffer);
		realBackBuffer->Release();

		// emulate flip queue behaviour exactly if required
		if(swapEffect == SWAP_FLIP && Settings::get().getEmulateFlipBehaviour() && !doNotFlip) {
			d3ddev->StretchRect(backBuffers[0]->getSurf(), NULL, extraBuffer->getSurf(), NULL, D3DTEXF_NONE);
			for(unsigned bb = 0; bb < numBackBuffers; ++bb) {
				d3ddev->StretchRect(backBuffers[bb + 1]->getSurf(), NULL, backBuffers[bb]->getSurf(), NULL, D3DTEXF_NONE);
			}
			d3ddev->StretchRect(extraBuffer->getSurf(), NULL, backBuffers[numBackBuffers - 1]->getSurf(), NULL, D3DTEXF_NONE);
			SDLOG(2, "Advanced flip queue\n");
		}
		else {
			SDLOG(2, "Not \"flipping\" backbuffers\n");
		}
		d3ddev->EndScene();
		restoreRenderState();
	}
	else {
		storeRenderState();
		d3ddev->BeginScene();
		IDirect3DSurface9* bb = NULL;
		d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &bb);
		if(dumpingFrame) {
			dumpSurface("framedump_preplugin", bb);
		}
		plugin->preDownsample(bb);
		if(dumpingFrame) {
			dumpSurface("framedump_postplugin", bb);
		}
		SAFERELEASE(bb);
		d3ddev->EndScene();
		restoreRenderState();
	}

	// Stop dumping
	if(dumpingFrame) {
		if(downsampling) {
			dumpSurface("framedump_prePresent", backBuffers[0]->getSurf());
		}
		SDLOG(0, "============================================\nFinished dumping frame.\n");
		Settings::get().restoreLogLevel();
		dumpingFrame = false;
		console.add("Finished dumping frame.");
	}


	// Full-size screenshots
	if(takingScreenshot(SCREENSHOT_FULL) || takingScreenshot(SCREENSHOT_HUDLESS)) {
		storeRenderState();
		if(downsampling) d3ddev->SetRenderTarget(0, backBuffers[0]->getSurf());
		captureRTScreen("full resolution");
		restoreRenderState();
		tookScreenshot(SCREENSHOT_FULL);
		tookScreenshot(SCREENSHOT_HUDLESS);
	}
	
	// Draw console
	if(console.needsDrawing()) {
		storeRenderState();
		// restore neutral state
		initStateBlock->Apply();
		d3ddev->BeginScene();
		IDirect3DSurface9* realBackBuffer;
		d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &realBackBuffer);
		if(realBackBuffer) d3ddev->SetRenderTarget(0, realBackBuffer);
		console.draw();
		if(realBackBuffer) realBackBuffer->Release();
		d3ddev->EndScene();
		restoreRenderState();
	}

	// Normal screenshots
	if(takingScreenshot(SCREENSHOT_STANDARD)) {
		storeRenderState();
		IDirect3DSurface9* realBackBuffer = NULL;
		d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &realBackBuffer);
		if(realBackBuffer) d3ddev->SetRenderTarget(0, realBackBuffer);
		captureRTScreen();
		SAFERELEASE(realBackBuffer);
		restoreRenderState();
		if(realBackBuffer) realBackBuffer->Release();
		tookScreenshot(SCREENSHOT_STANDARD);
	}

	// reset per-frame vars
	renderTargetSwitches = 0;
	plugin->prePresent();

	//////////////////////////////////////////// IO
	KeyActions::get().processIO();
	//////////////////////////////////////////// IO

	if(dumpingFrame) {
		Settings::get().elevateLogLevel(50);
		SDLOG(0, "============================================\nStarting frame dump.\n");
	}

	SDLOG(2, "Pre-present complete\n");
}