/* $Id: Present.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */ /** @file * VirtualBox Windows Guest Mesa3D - ID3DPresent and ID3DPresentGroup implementation. */ /* * Copyright (C) 2016-2023 Oracle and/or its affiliates. * * This file is part of VirtualBox base platform packages, as * available from https://www.virtualbox.org. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, in version 3 of the * License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * SPDX-License-Identifier: GPL-3.0-only */ #include "VBoxPresent.h" #include "VBoxGallium.h" #include #include #include #include "../../../common/wddm/VBoxMPIf.h" #define TRAPNOTIMPL do { \ ASMBreakpoint(); \ } while (0) const GUID IID_ID3DPresent = { 0x77D60E80, 0xF1E6, 0x11DF, { 0x9E, 0x39, 0x95, 0x0C, 0xDF, 0xD7, 0x20, 0x85 } }; const GUID IID_ID3DPresentGroup = { 0xB9C3016E, 0xF32A, 0x11DF, { 0x9C, 0x18, 0x92, 0xEA, 0xDE, 0xD7, 0x20, 0x85 } }; /* * Gallium D3D9 state tracker (nine) uses ID3DPresent interface to present (display) rendered buffers, * when IDirect3DDevice9::Present method is called. * * The WDDM driver uses this mechanism _only_ when running the embedded GaDrvTest code. * * I.e. during normal operations ID3DPresent interface is _not_ used. * * However 'nine' creates the buffers for the implicit swapchain. * * The implementation here simply stores the surface id and dimensions in D3DWindowBuffer * structure and tells the host to display the surface in PresentBuffer. * * Most of methods will trigger a breakpoint, because it its not expected that they willl be called. */ struct D3DWindowBuffer { uint32_t u32Width; uint32_t u32Height; uint32_t u32Sid; }; class WDDMPresentGroup; class WDDMPresent: public ID3DPresent { public: /* IUnknown */ virtual HRESULT WINAPI QueryInterface(REFIID riid, void **ppvObject); virtual ULONG WINAPI AddRef(); virtual ULONG WINAPI Release(); /* ID3DPresent */ virtual HRESULT WINAPI SetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode); virtual HRESULT WINAPI NewD3DWindowBufferFromDmaBuf(int dmaBufFd, int width, int height, int stride, int depth, int bpp, D3DWindowBuffer **out); virtual HRESULT WINAPI DestroyD3DWindowBuffer(D3DWindowBuffer *buffer); virtual HRESULT WINAPI WaitBufferReleased(D3DWindowBuffer *buffer); virtual HRESULT WINAPI FrontBufferCopy(D3DWindowBuffer *buffer); virtual HRESULT WINAPI PresentBuffer(D3DWindowBuffer *buffer, HWND hWndOverride, const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion, DWORD Flags); virtual HRESULT WINAPI GetRasterStatus(D3DRASTER_STATUS *pRasterStatus); virtual HRESULT WINAPI GetDisplayMode(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation); virtual HRESULT WINAPI GetPresentStats(D3DPRESENTSTATS *pStats); virtual HRESULT WINAPI GetCursorPos(POINT *pPoint); virtual HRESULT WINAPI SetCursorPos(POINT *pPoint); virtual HRESULT WINAPI SetCursor(void *pBitmap, POINT *pHotspot, BOOL bShow); virtual HRESULT WINAPI SetGammaRamp(const D3DGAMMARAMP *pRamp, HWND hWndOverride); virtual HRESULT WINAPI GetWindowInfo(HWND hWnd, int *width, int *height, int *depth); WDDMPresent(); virtual ~WDDMPresent(); HRESULT Init(WDDMPresentGroup *pPresentGroup, D3DPRESENT_PARAMETERS *pPresentationParameters); private: volatile ULONG mcRefs; WDDMPresentGroup *mpPresentGroup; }; class WDDMPresentGroup: public ID3DPresentGroup { public: /* IUnknown */ virtual HRESULT WINAPI QueryInterface(REFIID riid, void **ppvObject); virtual ULONG WINAPI AddRef(); virtual ULONG WINAPI Release(); /* ID3DPresentGroup */ virtual UINT WINAPI GetMultiheadCount(); virtual HRESULT WINAPI GetPresent(UINT Index, ID3DPresent **ppPresent); virtual HRESULT WINAPI CreateAdditionalPresent(D3DPRESENT_PARAMETERS *pPresentationParameters, ID3DPresent **ppPresent); virtual void WINAPI GetVersion(int *major, int *minor); WDDMPresentGroup(); virtual ~WDDMPresentGroup(); HRESULT Init(int cPresentBackends, IGaDirect3DDevice9Ex *pGaDevice); IGaDirect3DDevice9Ex *GaDevice() { return mpGaDevice; } private: volatile ULONG mcRefs; IGaDirect3DDevice9Ex *mpGaDevice; /** @todo ref count? */ int mcPresentBackends; WDDMPresent **mpaPresentBackends; }; /* * WDDMPresent implementation. */ WDDMPresent::WDDMPresent() : mcRefs(0) { } WDDMPresent::~WDDMPresent() { } HRESULT WDDMPresent::Init(WDDMPresentGroup *pPresentGroup, D3DPRESENT_PARAMETERS *pPresentationParameters) { RT_NOREF(pPresentationParameters); mpPresentGroup = pPresentGroup; return S_OK; } ULONG WINAPI WDDMPresent::AddRef() { ULONG refs = InterlockedIncrement(&mcRefs); return refs; } ULONG WINAPI WDDMPresent::Release() { ULONG refs = InterlockedDecrement(&mcRefs); if (refs == 0) { delete this; } return refs; } HRESULT WINAPI WDDMPresent::QueryInterface(REFIID riid, void **ppvObject) { if (!ppvObject) { return E_POINTER; } if ( IsEqualGUID(IID_IUnknown, riid) || IsEqualGUID(IID_ID3DPresent, riid)) { AddRef(); *ppvObject = this; return S_OK; } *ppvObject = NULL; return E_NOINTERFACE; } HRESULT WINAPI WDDMPresent::SetPresentParameters(D3DPRESENT_PARAMETERS *pPresentationParameters, D3DDISPLAYMODEEX *pFullscreenDisplayMode) { RT_NOREF(pPresentationParameters); RT_NOREF(pFullscreenDisplayMode); /* Ignore. */ return S_OK; } HRESULT WINAPI WDDMPresent::NewD3DWindowBufferFromDmaBuf(int dmaBufFd, int width, int height, int stride, int depth, int bpp, D3DWindowBuffer **out) { RT_NOREF3(stride, depth, bpp); D3DWindowBuffer *pBuffer = (D3DWindowBuffer *)RTMemAlloc(sizeof(D3DWindowBuffer)); if (!pBuffer) return E_OUTOFMEMORY; pBuffer->u32Width = width; pBuffer->u32Height = height; pBuffer->u32Sid = dmaBufFd; *out = pBuffer; return S_OK; } HRESULT WINAPI WDDMPresent::DestroyD3DWindowBuffer(D3DWindowBuffer *buffer) { RTMemFree(buffer); return S_OK; } HRESULT WINAPI WDDMPresent::WaitBufferReleased(D3DWindowBuffer *buffer) { RT_NOREF(buffer); /* Ignore */ return D3D_OK; } HRESULT WINAPI WDDMPresent::FrontBufferCopy(D3DWindowBuffer *buffer) { RT_NOREF(buffer); TRAPNOTIMPL; return D3DERR_INVALIDCALL; } HRESULT WINAPI WDDMPresent::PresentBuffer(D3DWindowBuffer *pBuffer, HWND hWndOverride, const RECT *pSourceRect, const RECT *pDestRect, const RGNDATA *pDirtyRegion, DWORD Flags) { RT_NOREF5(hWndOverride, pSourceRect, pDestRect, pDirtyRegion, Flags); ASMBreakpoint(); /* This is expected to run only as part of GaDrvTest under kernel debugger. */ IGaDirect3DDevice9Ex *pGaDevice = mpPresentGroup->GaDevice(); VBOXDISPIFESCAPE_GAPRESENT data; RT_ZERO(data); data.EscapeHdr.escapeCode = VBOXESC_GAPRESENT; data.u32Sid = pBuffer->u32Sid; data.u32Width = pBuffer->u32Width; data.u32Height = pBuffer->u32Height; HRESULT hr = pGaDevice->EscapeCb(&data, sizeof(data), /* fHardwareAccess= */ true); if (SUCCEEDED(hr)) return D3D_OK; return D3DERR_INVALIDCALL; } HRESULT WINAPI WDDMPresent::GetRasterStatus(D3DRASTER_STATUS *pRasterStatus) { RT_NOREF(pRasterStatus); TRAPNOTIMPL; return D3DERR_INVALIDCALL; } HRESULT WINAPI WDDMPresent::GetDisplayMode(D3DDISPLAYMODEEX *pMode, D3DDISPLAYROTATION *pRotation) { RT_NOREF2(pMode, pRotation); TRAPNOTIMPL; return D3DERR_INVALIDCALL; } HRESULT WINAPI WDDMPresent::GetPresentStats(D3DPRESENTSTATS *pStats) { RT_NOREF(pStats); TRAPNOTIMPL; return D3DERR_INVALIDCALL; } HRESULT WINAPI WDDMPresent::GetCursorPos(POINT *pPoint) { if (!::GetCursorPos(pPoint)) { pPoint->x = 0; pPoint->y = 0; } return S_OK; } HRESULT WINAPI WDDMPresent::SetCursorPos(POINT *pPoint) { RT_NOREF(pPoint); TRAPNOTIMPL; return D3DERR_INVALIDCALL; } HRESULT WINAPI WDDMPresent::SetCursor(void *pBitmap, POINT *pHotspot, BOOL bShow) { RT_NOREF3(pBitmap, pHotspot, bShow); TRAPNOTIMPL; return D3DERR_INVALIDCALL; } HRESULT WINAPI WDDMPresent::SetGammaRamp(const D3DGAMMARAMP *pRamp, HWND hWndOverride) { RT_NOREF2(pRamp, hWndOverride); TRAPNOTIMPL; return D3DERR_INVALIDCALL; } HRESULT WINAPI WDDMPresent::GetWindowInfo(HWND hWnd, int *width, int *height, int *depth) { RT_NOREF4(hWnd, width, height, depth); TRAPNOTIMPL; return D3DERR_INVALIDCALL; } /* * WDDMPresentGroup implementation. */ WDDMPresentGroup::WDDMPresentGroup() : mcRefs(0), mcPresentBackends(0), mpaPresentBackends(NULL) { } WDDMPresentGroup::~WDDMPresentGroup() { if (mpaPresentBackends) { int i; for (i = 0; i < mcPresentBackends; ++i) { if (mpaPresentBackends[i]) { mpaPresentBackends[i]->Release(); mpaPresentBackends[i] = NULL; } } RTMemFree(mpaPresentBackends); mpaPresentBackends = NULL; } } HRESULT WDDMPresentGroup::Init(int cPresentBackends, IGaDirect3DDevice9Ex *pGaDevice) { mpGaDevice = pGaDevice; mcPresentBackends = cPresentBackends; mpaPresentBackends = (WDDMPresent **)RTMemAllocZ(mcPresentBackends); if (!mpaPresentBackends) { return E_OUTOFMEMORY; } int i; for (i = 0; i < mcPresentBackends; ++i) { WDDMPresent *p = new WDDMPresent(); if (!p) { return E_OUTOFMEMORY; } HRESULT hr = p->Init(this, NULL); if (FAILED(hr)) { delete p; return hr; } p->AddRef(); mpaPresentBackends[i] = p; } return S_OK; } ULONG WINAPI WDDMPresentGroup::AddRef() { ULONG refs = InterlockedIncrement(&mcRefs); return refs; } ULONG WINAPI WDDMPresentGroup::Release() { ULONG refs = InterlockedDecrement(&mcRefs); if (refs == 0) { delete this; } return refs; } HRESULT WINAPI WDDMPresentGroup::QueryInterface(REFIID riid, void **ppvObject) { if (!ppvObject) { return E_POINTER; } if ( IsEqualGUID(IID_IUnknown, riid) || IsEqualGUID(IID_ID3DPresentGroup, riid)) { AddRef(); *ppvObject = this; return S_OK; } *ppvObject = NULL; return E_NOINTERFACE; } UINT WINAPI WDDMPresentGroup::GetMultiheadCount() { return mcPresentBackends; } HRESULT WINAPI WDDMPresentGroup::GetPresent(UINT Index, ID3DPresent **ppPresent) { if (Index >= GetMultiheadCount()) { return D3DERR_INVALIDCALL; } mpaPresentBackends[Index]->AddRef(); *ppPresent = mpaPresentBackends[Index]; return S_OK; } HRESULT WINAPI WDDMPresentGroup::CreateAdditionalPresent(D3DPRESENT_PARAMETERS *pPresentationParameters, ID3DPresent **ppPresent) { WDDMPresent *p = new WDDMPresent(); if (!p) { return E_OUTOFMEMORY; } HRESULT hr = p->Init(this, pPresentationParameters); if (SUCCEEDED(hr)) { p->AddRef(); *ppPresent = p; } else { delete p; } return hr; } void WINAPI WDDMPresentGroup::GetVersion(int *major, int *minor) { *major = 1; *minor = 0; } HRESULT WDDMPresentGroupCreate(IGaDirect3DDevice9Ex *pGaDevice, ID3DPresentGroup **ppOut) { WDDMPresentGroup *p = new WDDMPresentGroup(); if (!p) { return E_OUTOFMEMORY; } HRESULT hr = p->Init(1, pGaDevice); if (SUCCEEDED(hr)) { p->AddRef(); *ppOut = p; } else { delete p; } return hr; }