summaryrefslogtreecommitdiffstats
path: root/src/plugins/common/evr/evrd3dpresentengine.cpp
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@theqtcompany.com>2015-11-27 11:56:50 +0100
committerYoann Lopes <yoann.lopes@theqtcompany.com>2016-01-12 15:51:32 +0000
commitc7397523e77578cf8f09ba3258791f68c34e2e5f (patch)
tree9c293c768038f74564d411cd27cff5ce22ed46ac /src/plugins/common/evr/evrd3dpresentengine.cpp
parent36549dbe148055d6ecf98952b05b4ff2310fe491 (diff)
Windows: Improve EVR presenter.
Removed hard dependency to Angle; it's now required only when rendering to a texture. If Angle is not used, the buffers are now mappable to system memory. This enables HW-accelerated video decoding in QML for non-ANGLE builds. Note that the frame data have to do a round-trip through system memory, which is not ideal but still faster than SW decoding. Task-number: QTBUG-45593 Change-Id: Icc3503142df4e8dbb53b4e11f409b161fd2f9bde Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
Diffstat (limited to 'src/plugins/common/evr/evrd3dpresentengine.cpp')
-rw-r--r--src/plugins/common/evr/evrd3dpresentengine.cpp741
1 files changed, 362 insertions, 379 deletions
diff --git a/src/plugins/common/evr/evrd3dpresentengine.cpp b/src/plugins/common/evr/evrd3dpresentengine.cpp
index 61cee88d7..77cd7e0c8 100644
--- a/src/plugins/common/evr/evrd3dpresentengine.cpp
+++ b/src/plugins/common/evr/evrd3dpresentengine.cpp
@@ -35,48 +35,23 @@
#include "evrhelpers.h"
-#include <qtgui/qguiapplication.h>
-#include <qpa/qplatformnativeinterface.h>
-#include <qtgui/qopenglcontext.h>
#include <qabstractvideobuffer.h>
#include <QAbstractVideoSurface>
#include <qvideoframe.h>
#include <QDebug>
-#include <qopenglcontext.h>
-#include <qopenglfunctions.h>
-#include <qwindow.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <d3d9.h>
-#include <dxva2api.h>
-#include <WinUser.h>
-#include <evr.h>
+#include <qthread.h>
+#include <private/qmediaopenglhelper_p.h>
+
+#ifdef MAYBE_ANGLE
+# include <qtgui/qguiapplication.h>
+# include <qpa/qplatformnativeinterface.h>
+# include <qopenglfunctions.h>
+# include <EGL/eglext.h>
+#endif
static const int PRESENTER_BUFFER_COUNT = 3;
-class TextureVideoBuffer : public QAbstractVideoBuffer
-{
-public:
- TextureVideoBuffer(GLuint textureId)
- : QAbstractVideoBuffer(GLTextureHandle)
- , m_textureId(textureId)
- {}
-
- ~TextureVideoBuffer() {}
-
- MapMode mapMode() const { return NotMapped; }
- uchar *map(MapMode, int*, int*) { return 0; }
- void unmap() {}
-
- QVariant handle() const
- {
- return QVariant::fromValue<unsigned int>(m_textureId);
- }
-
-private:
- GLuint m_textureId;
-};
+#ifdef MAYBE_ANGLE
EGLWrapper::EGLWrapper()
{
@@ -140,22 +115,160 @@ EGLBoolean EGLWrapper::releaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLin
return m_eglReleaseTexImage(dpy, surface, buffer);
}
+
+class OpenGLResources : public QObject
+{
+public:
+ OpenGLResources()
+ : egl(new EGLWrapper)
+ , eglDisplay(0)
+ , eglSurface(0)
+ , glTexture(0)
+ {}
+
+ void release()
+ {
+ if (thread() == QThread::currentThread())
+ delete this;
+ else
+ deleteLater();
+ }
+
+ EGLWrapper *egl;
+ EGLDisplay *eglDisplay;
+ EGLSurface eglSurface;
+ unsigned int glTexture;
+
+private:
+ ~OpenGLResources()
+ {
+ Q_ASSERT(QOpenGLContext::currentContext() != NULL);
+
+ if (eglSurface && egl) {
+ egl->releaseTexImage(eglDisplay, eglSurface, EGL_BACK_BUFFER);
+ egl->destroySurface(eglDisplay, eglSurface);
+ }
+ if (glTexture)
+ QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &glTexture);
+
+ delete egl;
+ }
+};
+
+#endif // MAYBE_ANGLE
+
+
+class IMFSampleVideoBuffer: public QAbstractVideoBuffer
+{
+public:
+ IMFSampleVideoBuffer(D3DPresentEngine *engine, IMFSample *sample, QAbstractVideoBuffer::HandleType handleType)
+ : QAbstractVideoBuffer(handleType)
+ , m_engine(engine)
+ , m_sample(sample)
+ , m_surface(0)
+ , m_mapMode(NotMapped)
+ , m_textureUpdated(false)
+ {
+ if (m_sample) {
+ m_sample->AddRef();
+
+ IMFMediaBuffer *buffer;
+ if (SUCCEEDED(m_sample->GetBufferByIndex(0, &buffer))) {
+ MFGetService(buffer,
+ mr_BUFFER_SERVICE,
+ iid_IDirect3DSurface9,
+ reinterpret_cast<void **>(&m_surface));
+ buffer->Release();
+ }
+ }
+ }
+
+ ~IMFSampleVideoBuffer()
+ {
+ if (m_surface) {
+ if (m_mapMode != NotMapped)
+ m_surface->UnlockRect();
+ m_surface->Release();
+ }
+ if (m_sample)
+ m_sample->Release();
+ }
+
+ QVariant handle() const;
+
+ MapMode mapMode() const { return m_mapMode; }
+ uchar *map(MapMode, int*, int*);
+ void unmap();
+
+private:
+ mutable D3DPresentEngine *m_engine;
+ IMFSample *m_sample;
+ IDirect3DSurface9 *m_surface;
+ MapMode m_mapMode;
+ mutable bool m_textureUpdated;
+};
+
+uchar *IMFSampleVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
+{
+ if (!m_surface || m_mapMode != NotMapped)
+ return 0;
+
+ D3DSURFACE_DESC desc;
+ if (FAILED(m_surface->GetDesc(&desc)))
+ return 0;
+
+ D3DLOCKED_RECT rect;
+ if (FAILED(m_surface->LockRect(&rect, NULL, mode == ReadOnly ? D3DLOCK_READONLY : 0)))
+ return 0;
+
+ m_mapMode = mode;
+
+ if (numBytes)
+ *numBytes = (int)(rect.Pitch * desc.Height);
+
+ if (bytesPerLine)
+ *bytesPerLine = (int)rect.Pitch;
+
+ return reinterpret_cast<uchar *>(rect.pBits);
+}
+
+void IMFSampleVideoBuffer::unmap()
+{
+ if (m_mapMode == NotMapped)
+ return;
+
+ m_mapMode = NotMapped;
+ m_surface->UnlockRect();
+}
+
+QVariant IMFSampleVideoBuffer::handle() const
+{
+ QVariant handle;
+
+#ifdef MAYBE_ANGLE
+ if (handleType() != GLTextureHandle)
+ return handle;
+
+ if (m_textureUpdated || m_engine->updateTexture(m_surface)) {
+ m_textureUpdated = true;
+ handle = QVariant::fromValue<unsigned int>(m_engine->m_glResources->glTexture);
+ }
+#endif
+
+ return handle;
+}
+
+
D3DPresentEngine::D3DPresentEngine()
- : QObject()
- , m_mutex(QMutex::Recursive)
- , m_deviceResetToken(0)
+ : m_deviceResetToken(0)
, m_D3D9(0)
, m_device(0)
, m_deviceManager(0)
- , m_surface(0)
- , m_glContext(0)
- , m_offscreenSurface(0)
- , m_eglDisplay(0)
- , m_eglConfig(0)
- , m_eglSurface(0)
- , m_glTexture(0)
+ , m_useTextureRendering(false)
+#ifdef MAYBE_ANGLE
+ , m_glResources(0)
, m_texture(0)
- , m_egl(0)
+#endif
{
ZeroMemory(&m_displayMode, sizeof(m_displayMode));
@@ -172,47 +285,110 @@ D3DPresentEngine::D3DPresentEngine()
D3DPresentEngine::~D3DPresentEngine()
{
- qt_evr_safe_release(&m_texture);
+ releaseResources();
+
qt_evr_safe_release(&m_device);
qt_evr_safe_release(&m_deviceManager);
qt_evr_safe_release(&m_D3D9);
+}
- if (m_eglSurface) {
- m_egl->releaseTexImage(m_eglDisplay, m_eglSurface, EGL_BACK_BUFFER);
- m_egl->destroySurface(m_eglDisplay, m_eglSurface);
- m_eglSurface = NULL;
- }
- if (m_glTexture) {
- if (QOpenGLContext *current = QOpenGLContext::currentContext())
- current->functions()->glDeleteTextures(1, &m_glTexture);
- else
- qWarning() << "D3DPresentEngine: Cannot obtain GL context, unable to delete textures";
- }
+HRESULT D3DPresentEngine::initializeD3D()
+{
+ HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_D3D9);
- delete m_glContext;
- delete m_offscreenSurface;
- delete m_egl;
+ if (SUCCEEDED(hr))
+ hr = DXVA2CreateDirect3DDeviceManager9(&m_deviceResetToken, &m_deviceManager);
+
+ return hr;
}
-void D3DPresentEngine::start()
+HRESULT D3DPresentEngine::createD3DDevice()
{
- QMutexLocker locker(&m_mutex);
+ HRESULT hr = S_OK;
+ HWND hwnd = NULL;
+ UINT uAdapterID = D3DADAPTER_DEFAULT;
+ DWORD vp = 0;
- if (!m_surfaceFormat.isValid())
- return;
+ D3DCAPS9 ddCaps;
+ ZeroMemory(&ddCaps, sizeof(ddCaps));
+
+ IDirect3DDevice9Ex* device = NULL;
+
+ if (!m_D3D9 || !m_deviceManager)
+ return MF_E_NOT_INITIALIZED;
+
+ hwnd = ::GetShellWindow();
+
+ D3DPRESENT_PARAMETERS pp;
+ ZeroMemory(&pp, sizeof(pp));
+
+ pp.BackBufferWidth = 1;
+ pp.BackBufferHeight = 1;
+ pp.BackBufferFormat = D3DFMT_UNKNOWN;
+ pp.BackBufferCount = 1;
+ pp.Windowed = TRUE;
+ pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ pp.BackBufferFormat = D3DFMT_UNKNOWN;
+ pp.hDeviceWindow = hwnd;
+ pp.Flags = D3DPRESENTFLAG_VIDEO;
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
- if (!m_texture)
- createOffscreenTexture();
+ hr = m_D3D9->GetDeviceCaps(uAdapterID, D3DDEVTYPE_HAL, &ddCaps);
+ if (FAILED(hr))
+ goto done;
+
+ if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
+ vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
+ else
+ vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
- if (m_surface && !m_surface->isActive())
- m_surface->start(m_surfaceFormat);
+ hr = m_D3D9->CreateDeviceEx(
+ uAdapterID,
+ D3DDEVTYPE_HAL,
+ pp.hDeviceWindow,
+ vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
+ &pp,
+ NULL,
+ &device
+ );
+ if (FAILED(hr))
+ goto done;
+
+ hr = m_D3D9->GetAdapterDisplayMode(uAdapterID, &m_displayMode);
+ if (FAILED(hr))
+ goto done;
+
+ hr = m_deviceManager->ResetDevice(device, m_deviceResetToken);
+ if (FAILED(hr))
+ goto done;
+
+ qt_evr_safe_release(&m_device);
+
+ m_device = device;
+ m_device->AddRef();
+
+done:
+ qt_evr_safe_release(&device);
+ return hr;
}
-void D3DPresentEngine::stop()
+bool D3DPresentEngine::isValid() const
{
- QMutexLocker locker(&m_mutex);
- if (m_surface && m_surface->isActive())
- m_surface->stop();
+ return m_device != NULL;
+}
+
+void D3DPresentEngine::releaseResources()
+{
+ m_surfaceFormat = QVideoSurfaceFormat();
+
+#ifdef MAYBE_ANGLE
+ qt_evr_safe_release(&m_texture);
+
+ if (m_glResources) {
+ m_glResources->release(); // deleted in GL thread
+ m_glResources = NULL;
+ }
+#endif
}
HRESULT D3DPresentEngine::getService(REFGUID, REFIID riid, void** ppv)
@@ -235,33 +411,52 @@ HRESULT D3DPresentEngine::getService(REFGUID, REFIID riid, void** ppv)
HRESULT D3DPresentEngine::checkFormat(D3DFORMAT format)
{
- HRESULT hr = S_OK;
+ if (!m_D3D9 || !m_device)
+ return E_FAIL;
- UINT uAdapter = D3DADAPTER_DEFAULT;
- D3DDEVTYPE type = D3DDEVTYPE_HAL;
+ HRESULT hr = S_OK;
D3DDISPLAYMODE mode;
D3DDEVICE_CREATION_PARAMETERS params;
- // Our shared D3D/EGL surface only supports RGB32,
- // reject all other formats
- if (format != D3DFMT_X8R8G8B8)
- return MF_E_INVALIDMEDIATYPE;
-
- if (m_device) {
- hr = m_device->GetCreationParameters(&params);
- if (FAILED(hr))
- return hr;
+ hr = m_device->GetCreationParameters(&params);
+ if (FAILED(hr))
+ return hr;
- uAdapter = params.AdapterOrdinal;
- type = params.DeviceType;
- }
+ UINT uAdapter = params.AdapterOrdinal;
+ D3DDEVTYPE type = params.DeviceType;
hr = m_D3D9->GetAdapterDisplayMode(uAdapter, &mode);
if (FAILED(hr))
return hr;
- return m_D3D9->CheckDeviceType(uAdapter, type, mode.Format, format, TRUE);
+ hr = m_D3D9->CheckDeviceFormat(uAdapter, type, mode.Format,
+ D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_SURFACE,
+ format);
+
+ if (m_useTextureRendering && format != D3DFMT_X8R8G8B8 && format != D3DFMT_A8R8G8B8) {
+ // The texture is always in RGB32 so the d3d driver must support conversion from the
+ // requested format to RGB32.
+ hr = m_D3D9->CheckDeviceFormatConversion(uAdapter, type, format, D3DFMT_X8R8G8B8);
+ }
+
+ return hr;
+}
+
+bool D3DPresentEngine::supportsTextureRendering() const
+{
+#ifdef MAYBE_ANGLE
+ return QMediaOpenGLHelper::isANGLE();
+#else
+ return false;
+#endif
+}
+
+void D3DPresentEngine::setHint(Hint hint, bool enable)
+{
+ if (hint == RenderToTexture)
+ m_useTextureRendering = enable && supportsTextureRendering();
}
HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue)
@@ -270,211 +465,148 @@ HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSamp
return MF_E_UNEXPECTED;
HRESULT hr = S_OK;
- D3DPRESENT_PARAMETERS pp;
- IDirect3DSwapChain9 *swapChain = NULL;
+ IDirect3DSurface9 *surface = NULL;
IMFSample *videoSample = NULL;
- QMutexLocker locker(&m_mutex);
-
releaseResources();
- // Get the swap chain parameters from the media type.
- hr = getSwapChainPresentParameters(format, &pp);
+ UINT32 width = 0, height = 0;
+ hr = MFGetAttributeSize(format, MF_MT_FRAME_SIZE, &width, &height);
if (FAILED(hr))
- goto done;
+ return hr;
+
+ DWORD d3dFormat = 0;
+ hr = qt_evr_getFourCC(format, &d3dFormat);
+ if (FAILED(hr))
+ return hr;
// Create the video samples.
for (int i = 0; i < PRESENTER_BUFFER_COUNT; i++) {
- // Create a new swap chain.
- hr = m_device->CreateAdditionalSwapChain(&pp, &swapChain);
+ hr = m_device->CreateRenderTarget(width, height,
+ (D3DFORMAT)d3dFormat,
+ D3DMULTISAMPLE_NONE,
+ 0,
+ TRUE,
+ &surface, NULL);
if (FAILED(hr))
goto done;
- // Create the video sample from the swap chain.
- hr = createD3DSample(swapChain, &videoSample);
+ hr = MFCreateVideoSampleFromSurface(surface, &videoSample);
if (FAILED(hr))
goto done;
- // Add it to the list.
videoSample->AddRef();
videoSampleQueue.append(videoSample);
- // Set the swap chain pointer as a custom attribute on the sample. This keeps
- // a reference count on the swap chain, so that the swap chain is kept alive
- // for the duration of the sample's lifetime.
- hr = videoSample->SetUnknown(MFSamplePresenter_SampleSwapChain, swapChain);
- if (FAILED(hr))
- goto done;
-
qt_evr_safe_release(&videoSample);
- qt_evr_safe_release(&swapChain);
+ qt_evr_safe_release(&surface);
}
done:
- if (FAILED(hr))
+ if (SUCCEEDED(hr)) {
+ m_surfaceFormat = QVideoSurfaceFormat(QSize(width, height),
+ m_useTextureRendering ? QVideoFrame::Format_RGB32
+ : qt_evr_pixelFormatFromD3DFormat((D3DFORMAT)d3dFormat),
+ m_useTextureRendering ? QAbstractVideoBuffer::GLTextureHandle
+ : QAbstractVideoBuffer::NoHandle);
+ } else {
releaseResources();
+ }
- qt_evr_safe_release(&swapChain);
qt_evr_safe_release(&videoSample);
+ qt_evr_safe_release(&surface);
return hr;
}
-void D3DPresentEngine::releaseResources()
+QVideoFrame D3DPresentEngine::makeVideoFrame(IMFSample *sample)
{
-}
+ if (!sample)
+ return QVideoFrame();
-void D3DPresentEngine::presentSample(void *opaque, qint64)
-{
- HRESULT hr = S_OK;
+ QVideoFrame frame(new IMFSampleVideoBuffer(this, sample, m_surfaceFormat.handleType()),
+ m_surfaceFormat.frameSize(),
+ m_surfaceFormat.pixelFormat());
- IMFSample *sample = reinterpret_cast<IMFSample*>(opaque);
- IMFMediaBuffer* buffer = NULL;
- IDirect3DSurface9* surface = NULL;
-
- if (m_surface && m_surface->isActive()) {
- if (sample) {
- // Get the buffer from the sample.
- hr = sample->GetBufferByIndex(0, &buffer);
- if (FAILED(hr))
- goto done;
-
- // Get the surface from the buffer.
- hr = MFGetService(buffer, mr_BUFFER_SERVICE, IID_PPV_ARGS(&surface));
- if (FAILED(hr))
- goto done;
- }
+ // WMF uses 100-nanosecond units, Qt uses microseconds
+ LONGLONG startTime = -1;
+ if (SUCCEEDED(sample->GetSampleTime(&startTime))) {
+ frame.setStartTime(startTime * 0.1);
- if (surface && updateTexture(surface)) {
- QVideoFrame frame = QVideoFrame(new TextureVideoBuffer(m_glTexture),
- m_surfaceFormat.frameSize(),
- m_surfaceFormat.pixelFormat());
-
- // WMF uses 100-nanosecond units, Qt uses microseconds
- LONGLONG startTime = -1;
- if (SUCCEEDED(sample->GetSampleTime(&startTime))) {
- frame.setStartTime(startTime * 0.1);
-
- LONGLONG duration = -1;
- if (SUCCEEDED(sample->GetSampleDuration(&duration)))
- frame.setEndTime((startTime + duration) * 0.1);
- }
-
- m_surface->present(frame);
- }
+ LONGLONG duration = -1;
+ if (SUCCEEDED(sample->GetSampleDuration(&duration)))
+ frame.setEndTime((startTime + duration) * 0.1);
}
-done:
- qt_evr_safe_release(&surface);
- qt_evr_safe_release(&buffer);
- qt_evr_safe_release(&sample);
+ return frame;
}
-void D3DPresentEngine::setSurface(QAbstractVideoSurface *surface)
-{
- QMutexLocker locker(&m_mutex);
- m_surface = surface;
-}
+#ifdef MAYBE_ANGLE
-void D3DPresentEngine::setSurfaceFormat(const QVideoSurfaceFormat &format)
+bool D3DPresentEngine::createRenderTexture()
{
- QMutexLocker locker(&m_mutex);
- m_surfaceFormat = format;
-}
+ if (m_texture)
+ return true;
-void D3DPresentEngine::createOffscreenTexture()
-{
- // First, check if we have a context on this thread
- QOpenGLContext *currentContext = QOpenGLContext::currentContext();
-
- if (!currentContext) {
- //Create OpenGL context and set share context from surface
- QOpenGLContext *shareContext = qobject_cast<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>());
- if (!shareContext)
- return;
-
- m_offscreenSurface = new QWindow;
- m_offscreenSurface->setSurfaceType(QWindow::OpenGLSurface);
- //Needs geometry to be a valid surface, but size is not important
- m_offscreenSurface->setGeometry(-1, -1, 1, 1);
- m_offscreenSurface->create();
-
- m_glContext = new QOpenGLContext;
- m_glContext->setFormat(m_offscreenSurface->requestedFormat());
- m_glContext->setShareContext(shareContext);
-
- if (!m_glContext->create()) {
- delete m_glContext;
- delete m_offscreenSurface;
- m_glContext = 0;
- m_offscreenSurface = 0;
- return;
- }
-
- currentContext = m_glContext;
- }
+ Q_ASSERT(QOpenGLContext::currentContext() != NULL);
- if (m_glContext)
- m_glContext->makeCurrent(m_offscreenSurface);
+ if (!m_glResources)
+ m_glResources = new OpenGLResources;
- if (!m_egl)
- m_egl = new EGLWrapper;
+ QOpenGLContext *currentContext = QOpenGLContext::currentContext();
+ if (!currentContext)
+ return false;
QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
- m_eglDisplay = static_cast<EGLDisplay*>(
+ m_glResources->eglDisplay = static_cast<EGLDisplay*>(
nativeInterface->nativeResourceForContext("eglDisplay", currentContext));
- m_eglConfig = static_cast<EGLConfig*>(
+ EGLConfig *eglConfig = static_cast<EGLConfig*>(
nativeInterface->nativeResourceForContext("eglConfig", currentContext));
- currentContext->functions()->glGenTextures(1, &m_glTexture);
+ currentContext->functions()->glGenTextures(1, &m_glResources->glTexture);
- int w = m_surfaceFormat.frameWidth();
- int h = m_surfaceFormat.frameHeight();
bool hasAlpha = currentContext->format().hasAlpha();
EGLint attribs[] = {
- EGL_WIDTH, w,
- EGL_HEIGHT, h,
+ EGL_WIDTH, m_surfaceFormat.frameWidth(),
+ EGL_HEIGHT, m_surfaceFormat.frameHeight(),
EGL_TEXTURE_FORMAT, hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
EGL_NONE
};
- EGLSurface pbuffer = m_egl->createPbufferSurface(m_eglDisplay, m_eglConfig, attribs);
+ EGLSurface pbuffer = m_glResources->egl->createPbufferSurface(m_glResources->eglDisplay, eglConfig, attribs);
HANDLE share_handle = 0;
PFNEGLQUERYSURFACEPOINTERANGLEPROC eglQuerySurfacePointerANGLE =
- reinterpret_cast<PFNEGLQUERYSURFACEPOINTERANGLEPROC>(m_egl->getProcAddress("eglQuerySurfacePointerANGLE"));
+ reinterpret_cast<PFNEGLQUERYSURFACEPOINTERANGLEPROC>(m_glResources->egl->getProcAddress("eglQuerySurfacePointerANGLE"));
Q_ASSERT(eglQuerySurfacePointerANGLE);
eglQuerySurfacePointerANGLE(
- m_eglDisplay,
+ m_glResources->eglDisplay,
pbuffer,
EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, &share_handle);
- m_device->CreateTexture(w, h, 1,
+ m_device->CreateTexture(m_surfaceFormat.frameWidth(), m_surfaceFormat.frameHeight(), 1,
D3DUSAGE_RENDERTARGET,
hasAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8,
D3DPOOL_DEFAULT,
&m_texture,
&share_handle);
- m_eglSurface = pbuffer;
+ m_glResources->eglSurface = pbuffer;
+
+ QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, m_glResources->glTexture);
+ m_glResources->egl->bindTexImage(m_glResources->eglDisplay, m_glResources->eglSurface, EGL_BACK_BUFFER);
- if (m_glContext)
- m_glContext->doneCurrent();
+ return m_texture != NULL;
}
bool D3DPresentEngine::updateTexture(IDirect3DSurface9 *src)
{
- if (!m_texture)
+ if (!m_texture && !createRenderTexture())
return false;
- if (m_glContext)
- m_glContext->makeCurrent(m_offscreenSurface);
-
- QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, m_glTexture);
-
IDirect3DSurface9 *dest = NULL;
// Copy the sample surface to the shared D3D/EGL surface
@@ -483,173 +615,24 @@ bool D3DPresentEngine::updateTexture(IDirect3DSurface9 *src)
goto done;
hr = m_device->StretchRect(src, NULL, dest, NULL, D3DTEXF_NONE);
- if (FAILED(hr))
+ if (FAILED(hr)) {
qWarning("Failed to copy D3D surface");
-
- if (hr == S_OK)
- m_egl->bindTexImage(m_eglDisplay, m_eglSurface, EGL_BACK_BUFFER);
+ } else {
+ // Shared surfaces are not synchronized, there's no guarantee that
+ // StretchRect is complete when the texture is later rendered by Qt.
+ // To make sure the next rendered frame is up to date, flush the command pipeline
+ // using an event query.
+ IDirect3DQuery9 *eventQuery = NULL;
+ m_device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
+ eventQuery->Issue(D3DISSUE_END);
+ while (eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE);
+ eventQuery->Release();
+ }
done:
qt_evr_safe_release(&dest);
- if (m_glContext)
- m_glContext->doneCurrent();
-
return SUCCEEDED(hr);
}
-HRESULT D3DPresentEngine::initializeD3D()
-{
- HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_D3D9);
-
- if (SUCCEEDED(hr))
- hr = DXVA2CreateDirect3DDeviceManager9(&m_deviceResetToken, &m_deviceManager);
-
- return hr;
-}
-
-HRESULT D3DPresentEngine::createD3DDevice()
-{
- HRESULT hr = S_OK;
- HWND hwnd = NULL;
- UINT uAdapterID = D3DADAPTER_DEFAULT;
- DWORD vp = 0;
-
- D3DCAPS9 ddCaps;
- ZeroMemory(&ddCaps, sizeof(ddCaps));
-
- IDirect3DDevice9Ex* device = NULL;
-
- // Hold the lock because we might be discarding an existing device.
- QMutexLocker locker(&m_mutex);
-
- if (!m_D3D9 || !m_deviceManager)
- return MF_E_NOT_INITIALIZED;
-
- hwnd = ::GetShellWindow();
-
- // Note: The presenter creates additional swap chains to present the
- // video frames. Therefore, it does not use the device's implicit
- // swap chain, so the size of the back buffer here is 1 x 1.
-
- D3DPRESENT_PARAMETERS pp;
- ZeroMemory(&pp, sizeof(pp));
-
- pp.BackBufferWidth = 1;
- pp.BackBufferHeight = 1;
- pp.BackBufferFormat = D3DFMT_UNKNOWN;
- pp.BackBufferCount = 1;
- pp.Windowed = TRUE;
- pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
- pp.BackBufferFormat = D3DFMT_UNKNOWN;
- pp.hDeviceWindow = hwnd;
- pp.Flags = D3DPRESENTFLAG_VIDEO;
- pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
-
- hr = m_D3D9->GetDeviceCaps(uAdapterID, D3DDEVTYPE_HAL, &ddCaps);
- if (FAILED(hr))
- goto done;
-
- if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
- vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
- else
- vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
-
- hr = m_D3D9->CreateDeviceEx(
- uAdapterID,
- D3DDEVTYPE_HAL,
- pp.hDeviceWindow,
- vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
- &pp,
- NULL,
- &device
- );
- if (FAILED(hr))
- goto done;
-
- hr = m_D3D9->GetAdapterDisplayMode(uAdapterID, &m_displayMode);
- if (FAILED(hr))
- goto done;
-
- hr = m_deviceManager->ResetDevice(device, m_deviceResetToken);
- if (FAILED(hr))
- goto done;
-
- qt_evr_safe_release(&m_device);
-
- m_device = device;
- m_device->AddRef();
-
-done:
- qt_evr_safe_release(&device);
- return hr;
-}
-
-HRESULT D3DPresentEngine::createD3DSample(IDirect3DSwapChain9 *swapChain, IMFSample **videoSample)
-{
- D3DCOLOR clrBlack = D3DCOLOR_ARGB(0xFF, 0x00, 0x00, 0x00);
-
- IDirect3DSurface9* surface = NULL;
- IMFSample* sample = NULL;
-
- // Get the back buffer surface.
- HRESULT hr = swapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &surface);
- if (FAILED(hr))
- goto done;
-
- // Fill it with black.
- hr = m_device->ColorFill(surface, NULL, clrBlack);
- if (FAILED(hr))
- goto done;
-
- hr = MFCreateVideoSampleFromSurface(surface, &sample);
- if (FAILED(hr))
- goto done;
-
- *videoSample = sample;
- (*videoSample)->AddRef();
-
-done:
- qt_evr_safe_release(&surface);
- qt_evr_safe_release(&sample);
- return hr;
-}
-
-HRESULT D3DPresentEngine::getSwapChainPresentParameters(IMFMediaType *type, D3DPRESENT_PARAMETERS* pp)
-{
- ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS));
-
- // Get some information about the video format.
-
- UINT32 width = 0, height = 0;
-
- HRESULT hr = MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &width, &height);
- if (FAILED(hr))
- return hr;
-
- DWORD d3dFormat = 0;
-
- hr = qt_evr_getFourCC(type, &d3dFormat);
- if (FAILED(hr))
- return hr;
-
- ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS));
- pp->BackBufferWidth = width;
- pp->BackBufferHeight = height;
- pp->Windowed = TRUE;
- pp->SwapEffect = D3DSWAPEFFECT_DISCARD;
- pp->BackBufferFormat = (D3DFORMAT)d3dFormat;
- pp->hDeviceWindow = ::GetShellWindow();
- pp->Flags = D3DPRESENTFLAG_VIDEO;
- pp->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
-
- D3DDEVICE_CREATION_PARAMETERS params;
- hr = m_device->GetCreationParameters(&params);
- if (FAILED(hr))
- return hr;
-
- if (params.DeviceType != D3DDEVTYPE_HAL)
- pp->Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
-
- return S_OK;
-}
+#endif // MAYBE_ANGLE