Sign in to follow this  

Multiple swapchains, problems [DX9]

This topic is 3579 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've created a static-library interface, it can interface with two dynamic loading libraries. One of them uses DX9, the other one uses DX10. The problem I have is that I can tell the interface that I want to use more then one hWnd to render graphics to. I've created this in DX10, and it worked, I can (for example) tell the renderer to select window #1, and clear it to a certain color. I've never really used DX9, and this is where the problems started to appear, I can't select any window and clear it to a certain color. Here is the source code for the DX9 library (In the render loop, I first call the 'Clear(true, false)', then the 'BeginRendering()' and finally the 'EndRendering()' function):
HRESULT ShtrD3D::UseWindow(UINT nHwnd)
{
	LPDIRECT3DSURFACE9 pBack = NULL;

	if (!m_d3dpp.Windowed) {
		return S_OK;
	} else if (nHwnd >= m_nNumHWnd) {
		return E_FAIL;
	}

	if (FAILED(m_pd3dSwapChain[nHwnd]->GetBackBuffer(NULL, D3DBACKBUFFER_TYPE_MONO, &pBack))) {
		Log("ERROR: GetBackBuffer() failed in UseWindow()");
		return E_FAIL;
	}

	m_pd3dDevice->SetRenderTarget(0, pBack);
	pBack->Release();
	m_nActiveHWnd = nHwnd;

	return S_OK;
}

HRESULT ShtrD3D::BeginRendering()
{
	if (FAILED(m_pd3dDevice->BeginScene())) {
		return E_FAIL;
	}

	m_bIsSceneRunning = true;
	return S_OK;
}

HRESULT ShtrD3D::Clear(bool bClearPixel, bool bClearDepthStencil)
{
	DWORD dw = 0;

	if (bClearPixel) {
		dw |= D3DCLEAR_TARGET;
		dw |= D3DCLEAR_ZBUFFER;
	} if (bClearDepthStencil) {
		dw |= D3DCLEAR_STENCIL;
	}

	if (m_bIsSceneRunning) {
		m_pd3dDevice->EndScene();
	}

	if (FAILED(m_pd3dDevice->Clear(0, NULL, dw, m_ClearColor, 1.0f, 0))) {
		Log("ERROR: Clear failed\n");
		return E_FAIL;
	}

	if (m_bIsSceneRunning) {
		m_pd3dDevice->BeginScene();
	}

	return S_OK;
}

void ShtrD3D::EndRendering() 
{
	m_pd3dDevice->EndScene();
	m_pd3dDevice->Present(NULL, NULL, NULL, NULL);
	m_bIsSceneRunning = false;
}

void ShtrD3D::SetClearColor(float fRed, float fGreen, float fBlue)
{
	m_ClearColor = D3DCOLOR_COLORVALUE(fRed, fGreen, fBlue, 1.0f);
}
NOTE: I know some of the source code isn't correct, for example in the 'clear()' function, I'm going to fix that, but it should work like it is right now If it makes any difference, I initialize the DX9 device, object and swapchains like this:
HRESULT ShtrD3D::Init(HWND hWnd, const HWND *hWnd3D, int nNumHWnd, int nMinDepth, int nMinStencil, bool bSaveLog)
{
	m_Log.open("ShtrEngineLog.txt", std::ios::trunc);

	m_bSaveLog = bSaveLog;

	if (!m_Log.is_open()) {
		MessageBox(NULL, "Unable to load/create ShtrEngineLog.txt", "ShtrEngine - error", MB_OK | MB_ICONERROR);
		return E_FAIL;
	}

	if (nNumHWnd > MAX_3DHWND) {
		nNumHWnd = MAX_3DHWND;
	}

	if (nNumHWnd == 1) {
		m_hWnd[0] = hWnd;
		m_nNumHWnd = 1;
	} else {
		for (int i = 0; i < nNumHWnd; i++) {
			m_hWnd[i] = hWnd3D[i];
		}
		m_nNumHWnd = nNumHWnd;
	}

	m_hWndMain = hWnd;

	if (nMinStencil > 0) {
		m_bStencil = true;
	}

	Log("---------------------------------------------\n");
	Log("-----ShtrEngine Log File: DirectX 9       ---\n");
	Log("-----DLL and lib version 0.03 BETA        ---\n");
	Log("---------------------------------------------\n");
	Go();

	return S_OK;
}

HRESULT ShtrD3D::Go()
{
	if ( NULL == ( m_pd3d = Direct3DCreate9(D3D_SDK_VERSION))) {
		MessageBox(NULL, "Creating D3D9 object failed", "ShtrEngine - error", MB_OK | MB_ICONERROR);
		Log("ERROR: Creating D3D9 object failed\n");
		return E_FAIL;
	}

	ZeroMemory(&m_d3dpp, sizeof(m_d3dpp));

	m_d3dpp.BackBufferCount = 1;
	m_d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
	m_d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
	m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	m_d3dpp.Windowed = m_bWindowed;
	m_d3dpp.EnableAutoDepthStencil = TRUE;
	m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	if (!m_bWindowed) {
		Log("-----running in fullscreen mode           ---\n");
		Log("---------------------------------------------\n");
		m_d3dpp.BackBufferHeight = (UINT)400.0;
		m_d3dpp.BackBufferWidth = (UINT)600.0;
		m_d3dpp.hDeviceWindow = m_hWndMain;
	} else {
		Log("-----running in windowed mode             ---\n");
		Log("---------------------------------------------\n");
		m_d3dpp.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN);
		m_d3dpp.BackBufferWidth = GetSystemMetrics(SM_CXSCREEN);
		m_d3dpp.hDeviceWindow = m_hWnd[0];
	}

	m_fWidth = (float)m_d3dpp.BackBufferWidth;
	m_fHeight = (float)m_d3dpp.BackBufferHeight;

	HRESULT hr;

	Log("\n");
	Log("---------------------------------------------\n");
	Log("-----Creating d3dDevice and swap chains: ---\n");
	Log("---------------------------------------------\n");

	hr = m_pd3d->CreateDevice(D3DADAPTER_DEFAULT,
							  D3DDEVTYPE_HAL,
							  m_hWnd[0],
							  D3DCREATE_HARDWARE_VERTEXPROCESSING,
							  &m_d3dpp,
							  &m_pd3dDevice);

	if (FAILED(hr)) {
		MessageBox(NULL, "Creating D3D9 Device failed", "ShtrEngine - error", MB_OK | MB_ICONERROR);
		Log("ERROR: Creating D3D9 Device failed\n");
		return E_FAIL;
	}

	if (m_nNumHWnd > 0 && m_bWindowed) {
		for (UINT i = 0; i < m_nNumHWnd; i++) {
			m_d3dpp.hDeviceWindow = m_hWnd[i];
			hr = m_pd3dDevice->CreateAdditionalSwapChain(&m_d3dpp, &m_pd3dSwapChain[i]);

			if (FAILED(hr)) {
				MessageBox(NULL, "Creating D3D9 SwapChain failed", "ShtrEngine - error", MB_OK | MB_ICONERROR);
				Log("ERROR: Creating D3D9 Device failed || Iteration: " + i);
				return E_FAIL;
			}
		}
	}

	m_bRunning = true;
	m_bIsSceneRunning = false;

	Log("\nDirect3D succesfully initialized\n");
	Log("---------------------------------------------\n\n");

	return S_OK;
}

Share this post


Link to post
Share on other sites
You're missing calls to each swap chain's present call.

You don't call SetViewport. I've had situations where nothing would render when a SetViewport call was missing, even when setting the rendertarget to the surface which was already the active render target (an option to draw to another target was disabled if you're wondering why such a code path would exist.)

This next part is fine with your app as it is, I'm just pointing it out for your future development.

Typically swapchains have different sizes or AA settings, and would require their own Z buffers too. AutoDepthStencil doesn't work for swapchains (there is no call to query the surface pointer). Upon startup, get the device depthstencil surface (because once you set a new one, you'll have no way to query the one that came with your device. Another option is to never use AutoDepthStencil at all). Create your swapchains, and create Z buffers for your swap chains. Set your render target, depth buffer, and viewport for each swapchain in turn, and present them. As your windows are identical sizes, you can share the existing depth buffer.

If you are going to keep windows of the same size, and this isn't just quick test code, then you can even skip swapchains all together. Just pass a new HWND to present.

Also, be warned that creating depth buffers larger than the device's backbuffer with debug runtimes enabled will create buffers that will randomly work or fail. This may be limited to nVidia hardware, I'm not sure. Retail runtimes work, and buffers equal to or smaller than the backbuffer work too.

Share this post


Link to post
Share on other sites

This topic is 3579 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this