Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL) { IDirect3DDevice9 *device = getDevice(); D3DFORMAT requestedFormat = es2dx::ConvertRenderbufferFormat(format); int supportedSamples = getContext()->getNearestSupportedSamples(requestedFormat, samples); if (supportedSamples == -1) { error(GL_OUT_OF_MEMORY); return; } if (width > 0 && height > 0) { HRESULT result = device->CreateRenderTarget(width, height, requestedFormat, es2dx::GetMultisampleTypeFromSamples(supportedSamples), 0, FALSE, &mRenderTarget, NULL); if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) { error(GL_OUT_OF_MEMORY); return; } ASSERT(SUCCEEDED(result)); } mWidth = width; mHeight = height; mInternalFormat = format; mD3DFormat = requestedFormat; mSamples = supportedSamples; }
RenderTarget9::RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples) { mRenderer = Renderer9::makeRenderer9(renderer); mRenderTarget = NULL; D3DFORMAT renderFormat = gl_d3d9::GetRenderFormat(internalFormat, mRenderer); int supportedSamples = mRenderer->getNearestSupportedSamples(renderFormat, samples); if (supportedSamples == -1) { gl::error(GL_OUT_OF_MEMORY); return; } HRESULT result = D3DERR_INVALIDCALL; GLuint clientVersion = mRenderer->getCurrentClientVersion(); if (width > 0 && height > 0) { IDirect3DDevice9 *device = mRenderer->getDevice(); bool requiresInitialization = false; if (gl::GetDepthBits(internalFormat, clientVersion) > 0 || gl::GetStencilBits(internalFormat, clientVersion) > 0) { result = device->CreateDepthStencilSurface(width, height, renderFormat, gl_d3d9::GetMultisampleType(supportedSamples), 0, FALSE, &mRenderTarget, NULL); } else { requiresInitialization = gl_d3d9::RequiresTextureDataInitialization(internalFormat); result = device->CreateRenderTarget(width, height, renderFormat, gl_d3d9::GetMultisampleType(supportedSamples), 0, FALSE, &mRenderTarget, NULL); } if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_INVALIDARG || result == E_OUTOFMEMORY) { gl::error(GL_OUT_OF_MEMORY); return; } ASSERT(SUCCEEDED(result)); if (requiresInitialization) { // This format requires that the data be initialized before the render target can be used // Unfortunately this requires a Get call on the d3d device but it is far better than having // to mark the render target as lockable and copy data to the gpu. IDirect3DSurface9 *prevRenderTarget = NULL; device->GetRenderTarget(0, &prevRenderTarget); device->SetRenderTarget(0, mRenderTarget); device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); device->SetRenderTarget(0, prevRenderTarget); } } mWidth = width; mHeight = height; mDepth = 1; mInternalFormat = internalFormat; mSamples = supportedSamples; mActualFormat = d3d9_gl::GetInternalFormat(renderFormat); }
bool Texture2D::Create() { Release(); if (!graphics_ || !width_ || !height_) return false; if (graphics_->IsDeviceLost()) { URHO3D_LOGWARNING("Texture creation while device is lost"); return true; } if (multiSample_ > 1 && !autoResolve_) { URHO3D_LOGWARNING("Multisampled texture without autoresolve is not supported on Direct3D9"); autoResolve_ = true; } GraphicsImpl* impl = graphics_->GetImpl(); unsigned pool = usage_ > TEXTURE_STATIC ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; unsigned d3dUsage = 0; switch (usage_) { case TEXTURE_DYNAMIC: d3dUsage |= D3DUSAGE_DYNAMIC; break; case TEXTURE_RENDERTARGET: d3dUsage |= D3DUSAGE_RENDERTARGET; if (requestedLevels_ != 1) { // Check mipmap autogeneration support if (impl->CheckFormatSupport((D3DFORMAT)format_, D3DUSAGE_AUTOGENMIPMAP, D3DRTYPE_TEXTURE)) { requestedLevels_ = 0; d3dUsage |= D3DUSAGE_AUTOGENMIPMAP; } else requestedLevels_ = 1; } break; case TEXTURE_DEPTHSTENCIL: d3dUsage |= D3DUSAGE_DEPTHSTENCIL; // No mipmaps for depth-stencil textures requestedLevels_ = 1; break; default: break; } if (multiSample_ > 1) { // Fall back to non-multisampled if unsupported multisampling mode if (!impl->CheckMultiSampleSupport((D3DFORMAT)format_, multiSample_)) { multiSample_ = 1; autoResolve_ = false; } } IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice(); // If creating a depth-stencil texture, and it is not supported, create a depth-stencil surface instead // Multisampled surfaces need also to be created this way if (usage_ == TEXTURE_DEPTHSTENCIL && (multiSample_ > 1 || !graphics_->GetImpl()->CheckFormatSupport((D3DFORMAT)format_, d3dUsage, D3DRTYPE_TEXTURE))) { HRESULT hr = device->CreateDepthStencilSurface( (UINT)width_, (UINT)height_, (D3DFORMAT)format_, (multiSample_ > 1) ? (D3DMULTISAMPLE_TYPE)multiSample_ : D3DMULTISAMPLE_NONE, 0, FALSE, (IDirect3DSurface9**)&renderSurface_->surface_, nullptr); if (FAILED(hr)) { URHO3D_LOGD3DERROR("Could not create depth-stencil surface", hr); URHO3D_SAFE_RELEASE(renderSurface_->surface_); return false; } levels_ = 1; } else { HRESULT hr = graphics_->GetImpl()->GetDevice()->CreateTexture( (UINT)width_, (UINT)height_, requestedLevels_, d3dUsage, (D3DFORMAT)format_, (D3DPOOL)pool, (IDirect3DTexture9**)&object_, nullptr); if (FAILED(hr)) { URHO3D_LOGD3DERROR("Could not create texture", hr); URHO3D_SAFE_RELEASE(object_.ptr_); return false; } levels_ = ((IDirect3DTexture9*)object_.ptr_)->GetLevelCount(); // Create the multisampled rendertarget for rendering to if necessary if (usage_ == TEXTURE_RENDERTARGET && multiSample_ > 1) { HRESULT hr = device->CreateRenderTarget( (UINT)width_, (UINT)height_, (D3DFORMAT)format_, (D3DMULTISAMPLE_TYPE)multiSample_, 0, FALSE, (IDirect3DSurface9**)&renderSurface_->surface_, nullptr); if (FAILED(hr)) { URHO3D_LOGD3DERROR("Could not create multisampled rendertarget surface", hr); URHO3D_SAFE_RELEASE(renderSurface_->surface_); return false; } } else if (usage_ >= TEXTURE_RENDERTARGET) { // Else use the texture surface directly for rendering hr = ((IDirect3DTexture9*)object_.ptr_)->GetSurfaceLevel(0, (IDirect3DSurface9**)&renderSurface_->surface_); if (FAILED(hr)) { URHO3D_LOGD3DERROR("Could not get rendertarget surface", hr); URHO3D_SAFE_RELEASE(renderSurface_->surface_); return false; } } } return true; }
bool TextureCube::Create() { Release(); if (!graphics_ || !width_ || !height_) return false; if (graphics_->IsDeviceLost()) { URHO3D_LOGWARNING("Texture creation while device is lost"); return true; } GraphicsImpl* impl = graphics_->GetImpl(); unsigned pool = usage_ > TEXTURE_STATIC ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; unsigned d3dUsage = 0; switch (usage_) { case TEXTURE_DYNAMIC: d3dUsage |= D3DUSAGE_DYNAMIC; break; case TEXTURE_RENDERTARGET: d3dUsage |= D3DUSAGE_RENDERTARGET; if (requestedLevels_ != 1) { // Check mipmap autogeneration support if (impl->CheckFormatSupport((D3DFORMAT)format_, D3DUSAGE_AUTOGENMIPMAP, D3DRTYPE_TEXTURE)) { requestedLevels_ = 0; d3dUsage |= D3DUSAGE_AUTOGENMIPMAP; } else requestedLevels_ = 1; } break; default: break; } if (multiSample_ > 1) { // Fall back to non-multisampled if unsupported multisampling mode GraphicsImpl* impl = graphics_->GetImpl(); if (!impl->CheckMultiSampleSupport((D3DFORMAT)format_, multiSample_)) { multiSample_ = 1; autoResolve_ = false; } } IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice(); HRESULT hr = device->CreateCubeTexture( (UINT)width_, requestedLevels_, d3dUsage, (D3DFORMAT)format_, (D3DPOOL)pool, (IDirect3DCubeTexture9**)&object_.ptr_, nullptr); if (FAILED(hr)) { URHO3D_LOGD3DERROR("Could not create cube texture", hr); URHO3D_SAFE_RELEASE(object_.ptr_); return false; } levels_ = ((IDirect3DCubeTexture9*)object_.ptr_)->GetLevelCount(); if (usage_ == TEXTURE_RENDERTARGET) { for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i) { if (multiSample_ > 1) { // Create the multisampled face rendertarget if necessary HRESULT hr = device->CreateRenderTarget( (UINT)width_, (UINT)height_, (D3DFORMAT)format_, (D3DMULTISAMPLE_TYPE)multiSample_, 0, FALSE, (IDirect3DSurface9**)&renderSurfaces_[i]->surface_, nullptr); if (FAILED(hr)) { URHO3D_LOGD3DERROR("Could not create multisampled rendertarget surface", hr); URHO3D_SAFE_RELEASE(renderSurfaces_[i]->surface_); return false; } } else { hr = ((IDirect3DCubeTexture9*)object_.ptr_)->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, (IDirect3DSurface9**)&renderSurfaces_[i]->surface_); if (FAILED(hr)) { URHO3D_LOGD3DERROR("Could not get rendertarget surface", hr); URHO3D_SAFE_RELEASE(renderSurfaces_[i]->surface_); return false; } } } } return true; }
HRESULT WINAPI D3D9SCPresent(IDirect3DSwapChain9 *pSc, CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion, DWORD dwFlags) { D3D9FrameGrabber *d3d9FrameGrabber = D3D9FrameGrabber::getInstance(); Logger *logger = d3d9FrameGrabber->m_logger; DWORD errorcode; if (WAIT_OBJECT_0 == (errorcode = WaitForSingleObject(d3d9FrameGrabber->m_syncRunMutex, 0))) { IPCContext *ipcContext = d3d9FrameGrabber->m_ipcContext; logger->reportLogDebug(L"D3D9SCPresent"); IDirect3DSurface9 *pBackBuffer = NULL; D3DPRESENT_PARAMETERS params; RECT newRect = RECT(); IDirect3DSurface9 *pDemultisampledSurf = NULL; IDirect3DSurface9 *pOffscreenSurf = NULL; IDirect3DDevice9 *pDev = NULL; HRESULT hRes = pSc->GetPresentParameters(¶ms); if (FAILED(hRes) || params.Windowed) { goto end; } if (FAILED(hRes = pSc->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) { logger->reportLogError(L"d3d9sc couldn't get backbuffer. errorcode = 0x%x", hRes); goto end; } D3DSURFACE_DESC surfDesc; pBackBuffer->GetDesc(&surfDesc); hRes = pSc->GetDevice(&pDev); if (FAILED(hRes)) { logger->reportLogError(L"GetFramePrep: FAILED to get pDev. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format ); goto end; } hRes = pDev->CreateRenderTarget( surfDesc.Width, surfDesc.Height, surfDesc.Format, D3DMULTISAMPLE_NONE, 0, false, &pDemultisampledSurf, NULL ); if (FAILED(hRes)) { logger->reportLogError(L"GetFramePrep: FAILED to create demultisampled render target. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format ); goto end; } hRes = pDev->StretchRect(pBackBuffer, NULL, pDemultisampledSurf, NULL, D3DTEXF_LINEAR ); if (FAILED(hRes)) { logger->reportLogError(L"GetFramePrep: StretchRect FAILED for image surfacee. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format ); goto end; } hRes = pDev->CreateOffscreenPlainSurface( surfDesc.Width, surfDesc.Height, surfDesc.Format, D3DPOOL_SYSTEMMEM, &pOffscreenSurf, NULL ); if (FAILED(hRes)) { logger->reportLogError(L"GetFramePrep: FAILED to create image surface. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format ); goto end; } hRes = pDev->GetRenderTargetData(pDemultisampledSurf, pOffscreenSurf ); if (FAILED(hRes)) { logger->reportLogError(L"GetFramePrep: GetRenderTargetData() FAILED for image surfacee. 0x%x, width=%u, height=%u, format=%x", hRes, surfDesc.Width, surfDesc.Height, surfDesc.Format ); goto end; } D3DLOCKED_RECT lockedSrcRect; newRect.right = surfDesc.Width; newRect.bottom = surfDesc.Height; hRes = pOffscreenSurf->LockRect( &lockedSrcRect, &newRect, 0); if (FAILED(hRes)) { logger->reportLogError(L"GetFramePrep: FAILED to lock source rect. (0x%x)", hRes ); goto end; } ipcContext->m_memDesc.width = surfDesc.Width; ipcContext->m_memDesc.height = surfDesc.Height; ipcContext->m_memDesc.rowPitch = lockedSrcRect.Pitch; ipcContext->m_memDesc.frameId++; ipcContext->m_memDesc.format = getCompatibleBufferFormat(surfDesc.Format); if (WAIT_OBJECT_0 == (errorcode = WaitForSingleObject(ipcContext->m_hMutex, 0))) { // __asm__("int $3"); // reportLog(EVENTLOG_INFORMATION_TYPE, L"d3d9sc writing description to mem mapped file"); memcpy(ipcContext->m_pMemMap, &ipcContext->m_memDesc, sizeof (ipcContext->m_memDesc)); // reportLog(EVENTLOG_INFORMATION_TYPE, L"d3d9sc writing data to mem mapped file"); PVOID pMemDataMap = incPtr(ipcContext->m_pMemMap, sizeof (ipcContext->m_memDesc)); if (static_cast<UINT>(lockedSrcRect.Pitch) == surfDesc.Width * 4) { memcpy(pMemDataMap, lockedSrcRect.pBits, surfDesc.Width * surfDesc.Height * 4); } else { UINT i = 0, cleanOffset = 0, pitchOffset = 0; while (i < surfDesc.Height) { memcpy(incPtr(pMemDataMap, cleanOffset), incPtr(lockedSrcRect.pBits, pitchOffset), surfDesc.Width * 4); cleanOffset += surfDesc.Width * 4; pitchOffset += lockedSrcRect.Pitch; i++; } } ReleaseMutex(ipcContext->m_hMutex); SetEvent(ipcContext->m_hFrameGrabbedEvent); } else { logger->reportLogError(L"d3d9sc couldn't wait mutex. errocode = 0x%x", errorcode); } end: if(pOffscreenSurf) pOffscreenSurf->Release(); if(pDemultisampledSurf) pDemultisampledSurf->Release(); if(pBackBuffer) pBackBuffer->Release(); if(pDev) pDev->Release(); ProxyFuncJmp *d3d9SCPresentProxyFuncJmp = d3d9FrameGrabber->m_d3d9SCPresentProxyFuncJmp; if(d3d9SCPresentProxyFuncJmp->removeHook()) { int i = GetLastError(); logger->reportLogError(L"d3d9sc error occured while trying to removeHook before original call0x%x", i); } HRESULT result = pSc->Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); if(d3d9SCPresentProxyFuncJmp->installHook()) { int i = GetLastError(); logger->reportLogError(L"d3d9sc error occured while trying to installHook after original call0x%x", i); } ReleaseMutex(d3d9FrameGrabber->m_syncRunMutex); return result; } else { logger->reportLogError(L"d3d9sc present is skipped because mutex is busy"); return S_FALSE; } }
void Surface::resetSwapChain() { IDirect3DDevice9 *device = mDisplay->getDevice(); D3DPRESENT_PARAMETERS presentParameters = {0}; presentParameters.AutoDepthStencilFormat = mConfig->mDepthStencilFormat; presentParameters.BackBufferCount = 1; presentParameters.BackBufferFormat = mConfig->mRenderTargetFormat; presentParameters.EnableAutoDepthStencil = FALSE; presentParameters.Flags = 0; presentParameters.hDeviceWindow = getWindowHandle(); presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented presentParameters.PresentationInterval = Display::convertInterval(mConfig->mMinSwapInterval); presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; presentParameters.Windowed = TRUE; RECT windowRect; if (!GetClientRect(getWindowHandle(), &windowRect)) { ASSERT(false); return; } presentParameters.BackBufferWidth = windowRect.right - windowRect.left; presentParameters.BackBufferHeight = windowRect.bottom - windowRect.top; IDirect3DSwapChain9 *swapChain = NULL; HRESULT result = device->CreateAdditionalSwapChain(&presentParameters, &swapChain); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); ERR("Could not create additional swap chains: %08lX", result); return error(EGL_BAD_ALLOC); } IDirect3DSurface9 *depthStencilSurface = NULL; result = device->CreateDepthStencilSurface(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, presentParameters.AutoDepthStencilFormat, presentParameters.MultiSampleType, presentParameters.MultiSampleQuality, FALSE, &depthStencilSurface, NULL); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); swapChain->Release(); ERR("Could not create depthstencil surface for new swap chain: %08lX", result); return error(EGL_BAD_ALLOC); } IDirect3DSurface9 *renderTarget = NULL; result = device->CreateRenderTarget(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, presentParameters.BackBufferFormat, presentParameters.MultiSampleType, presentParameters.MultiSampleQuality, FALSE, &renderTarget, NULL); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); swapChain->Release(); depthStencilSurface->Release(); ERR("Could not create render target surface for new swap chain: %08lX", result); return error(EGL_BAD_ALLOC); } ASSERT(SUCCEEDED(result)); IDirect3DTexture9 *flipTexture = NULL; result = device->CreateTexture(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, 1, D3DUSAGE_RENDERTARGET, presentParameters.BackBufferFormat, D3DPOOL_DEFAULT, &flipTexture, NULL); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); swapChain->Release(); depthStencilSurface->Release(); renderTarget->Release(); ERR("Could not create flip texture for new swap chain: %08lX", result); return error(EGL_BAD_ALLOC); } IDirect3DSurface9 *backBuffer = NULL; swapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backBuffer); if (mSwapChain) mSwapChain->Release(); if (mDepthStencil) mDepthStencil->Release(); if (mBackBuffer) mBackBuffer->Release(); if (mRenderTarget) mRenderTarget->Release(); if (mFlipTexture) mFlipTexture->Release(); mWidth = presentParameters.BackBufferWidth; mHeight = presentParameters.BackBufferHeight; mSwapChain = swapChain; mDepthStencil = depthStencilSurface; mBackBuffer = backBuffer; mRenderTarget = renderTarget; mFlipTexture = flipTexture; // The flip state block recorded mFlipTexture so it is now invalid. releaseRecordedState(device); }