6#include <QtMultimediaTestLib/private/qvideoframetestutils_p.h>
8#include <QtGui/rhi/qrhi.h>
10#include <QtCore/private/qsystemerror_p.h>
18UINT sliceSubresource(
const ComPtr<ID3D11Texture2D> &texture, UINT arraySlice)
20 D3D11_TEXTURE2D_DESC desc{};
21 texture->GetDesc(&desc);
22 return D3D11CalcSubresource(0, arraySlice, desc.MipLevels);
31 D3D11_TEXTURE2D_DESC desc{};
32 texture->GetDesc(&desc);
35 D3D11_TEXTURE2D_DESC stagingDesc = desc;
36 stagingDesc.Usage = D3D11_USAGE_STAGING;
37 stagingDesc.BindFlags = 0;
38 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
39 stagingDesc.MiscFlags = 0;
41 ComPtr<ID3D11Texture2D> stagingTexture;
42 HRESULT hr = device->CreateTexture2D(&stagingDesc,
nullptr, &stagingTexture);
44 qWarning() <<
"Failed to create staging texture for first pixel read"
45 << QSystemError::windowsComString(hr);
46 return q23::unexpected{ hr };
50 context->CopyResource(stagingTexture.Get(), texture.Get());
53 D3D11_MAPPED_SUBRESOURCE mappedResource{};
54 hr = context->Map(stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mappedResource);
56 qWarning() <<
"Failed to map staging texture for first pixel read"
57 << QSystemError::windowsComString(hr);
58 return q23::unexpected{ hr };
62 unsigned char *data =
static_cast<
unsigned char *>(mappedResource.pData);
64 QColor firstPixel{ data[0], data[1], data[2], data[3] };
67 context->Unmap(stagingTexture.Get(), 0);
75 D3D11_TEXTURE2D_DESC desc{};
76 texture->GetDesc(&desc);
78 D3D11_TEXTURE2D_DESC stagingDesc = desc;
79 stagingDesc.Usage = D3D11_USAGE_STAGING;
80 stagingDesc.BindFlags = 0;
81 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
82 stagingDesc.MiscFlags = 0;
84 ComPtr<ID3D11Texture2D> stagingTexture;
85 HRESULT hr = device->CreateTexture2D(&stagingDesc,
nullptr, &stagingTexture);
87 return q23::unexpected{ hr };
89 context->CopyResource(stagingTexture.Get(), texture.Get());
91 D3D11_MAPPED_SUBRESOURCE mappedResource{};
92 hr = context->Map(stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mappedResource);
94 return q23::unexpected{ hr };
96 unsigned char *data =
static_cast<
unsigned char *>(mappedResource.pData);
98 QColor firstPixel{ data[2], data[1], data[0], data[3] };
100 context->Unmap(stagingTexture.Get(), 0);
107 const std::vector<QColor> &colors)
const
109 D3D11_TEXTURE2D_DESC texDesc{};
110 texDesc.Width = size.width();
111 texDesc.Height = size.height();
112 texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
113 texDesc.Usage = D3D11_USAGE_DEFAULT;
114 texDesc.CPUAccessFlags = 0;
115 texDesc.MiscFlags = 0;
116 texDesc.BindFlags = 0;
117 texDesc.ArraySize =
static_cast<UINT>(colors.size());
118 texDesc.MipLevels = 1;
119 texDesc.SampleDesc = { 1, 0 };
121 ComPtr<ID3D11Texture2D> tex;
122 HRESULT hr = device->CreateTexture2D(&texDesc,
nullptr, tex.GetAddressOf());
125 qWarning() <<
"Failed to create texture array" << QSystemError::windowsComString(hr);
126 return q23::unexpected{ hr };
129 hr = fillTextureWithColors(tex, colors);
131 qWarning() <<
"Failed to fill texture array" << QSystemError::windowsComString(hr);
132 return q23::unexpected{ hr };
143 UINT formatSupport = 0;
144 const HRESULT hr = device->CheckFormatSupport(format, &formatSupport);
148 return (formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0;
154 D3D11_TEXTURE2D_DESC texDesc{};
155 texDesc.Width = size.width();
156 texDesc.Height = size.height();
157 texDesc.Format = DXGI_FORMAT_NV12;
158 texDesc.Usage = D3D11_USAGE_DEFAULT;
159 texDesc.CPUAccessFlags = 0;
160 texDesc.MiscFlags = 0;
161 texDesc.BindFlags = 0;
162 texDesc.ArraySize = 1;
163 texDesc.MipLevels = 1;
164 texDesc.SampleDesc = { 1, 0 };
166 ComPtr<ID3D11Texture2D> tex;
167 HRESULT hr = device->CreateTexture2D(&texDesc,
nullptr, tex.GetAddressOf());
169 qWarning() <<
"Failed to create NV12 texture" << QSystemError::windowsComString(hr);
170 return q23::unexpected{ hr };
177 QSize size, quint8 lumaValue,
178 quint8 chromaUValue, quint8 chromaVValue,
179 UINT arraySlice)
const
181 const ComResult<ComPtr<ID3D11Texture2D>> staging =
182 createStagingSliceCopy(texture, arraySlice, D3D11_CPU_ACCESS_WRITE);
184 qWarning() <<
"Failed to create staging texture for NV12 fill"
185 << QSystemError::windowsComString(staging.error());
186 return staging.error();
188 const ComPtr<ID3D11Texture2D> &stagingTexture = *staging;
190 D3D11_MAPPED_SUBRESOURCE mappedResource{};
191 HRESULT hr = context->Map(stagingTexture.Get(), 0, D3D11_MAP_WRITE, 0, &mappedResource);
193 qWarning() <<
"Failed to map staging texture for NV12 fill"
194 << QSystemError::windowsComString(hr);
198 unsigned char *data =
static_cast<
unsigned char *>(mappedResource.pData);
199 const int width = size.width();
200 const int height = size.height();
203 for (
int row = 0; row < height; ++row) {
204 unsigned char *rowData = data + row * mappedResource.RowPitch;
205 std::fill(rowData, rowData + width, lumaValue);
210 unsigned char *chromaBase = data + height * mappedResource.RowPitch;
211 for (
int row = 0; row < height / 2; ++row) {
212 unsigned char *rowData = chromaBase + row * mappedResource.RowPitch;
213 for (
int col = 0; col < width / 2; ++col) {
214 rowData[2 * col] = chromaUValue;
215 rowData[2 * col + 1] = chromaVValue;
219 context->Unmap(stagingTexture.Get(), 0);
220 context->CopySubresourceRegion(texture.Get(), sliceSubresource(texture, arraySlice), 0, 0, 0,
221 stagingTexture.Get(), 0,
nullptr);
228 quint8 chromaU, quint8 chromaV)
const
230 const ComResult<ComPtr<ID3D11Texture2D>> tex = createNV12Texture(size);
234 const HRESULT hr = fillNV12Texture(*tex, size, lumaValue, chromaU, chromaV);
236 return q23::unexpected{ hr };
244 D3D11_TEXTURE2D_DESC texDesc{};
245 texDesc.Width = size.width();
246 texDesc.Height = size.height();
247 texDesc.Format = DXGI_FORMAT_P010;
248 texDesc.Usage = D3D11_USAGE_DEFAULT;
249 texDesc.CPUAccessFlags = 0;
250 texDesc.MiscFlags = 0;
251 texDesc.BindFlags = 0;
252 texDesc.ArraySize = 1;
253 texDesc.MipLevels = 1;
254 texDesc.SampleDesc = { 1, 0 };
256 ComPtr<ID3D11Texture2D> tex;
257 HRESULT hr = device->CreateTexture2D(&texDesc,
nullptr, tex.GetAddressOf());
259 qWarning() <<
"Failed to create P010 texture" << QSystemError::windowsComString(hr);
260 return q23::unexpected{ hr };
267 QSize size, quint16 lumaValue,
268 quint16 chromaUValue, quint16 chromaVValue,
269 UINT arraySlice)
const
271 const ComResult<ComPtr<ID3D11Texture2D>> staging =
272 createStagingSliceCopy(texture, arraySlice, D3D11_CPU_ACCESS_WRITE);
274 qWarning() <<
"Failed to create staging texture for P010 fill"
275 << QSystemError::windowsComString(staging.error());
276 return staging.error();
278 const ComPtr<ID3D11Texture2D> &stagingTexture = *staging;
280 D3D11_MAPPED_SUBRESOURCE mappedResource{};
281 HRESULT hr = context->Map(stagingTexture.Get(), 0, D3D11_MAP_WRITE, 0, &mappedResource);
283 qWarning() <<
"Failed to map staging texture for P010 fill"
284 << QSystemError::windowsComString(hr);
288 unsigned char *data =
static_cast<
unsigned char *>(mappedResource.pData);
292 const quint16 shiftedLuma = quint16(lumaValue << 6);
293 const char lumaTexel[2] = {
char(shiftedLuma & 0xff),
char(shiftedLuma >> 8) };
294 QtMultimediaTest::fillPlaneRows(data, mappedResource.RowPitch, size.width(), size.height(),
295 QByteArrayView(lumaTexel,
sizeof(lumaTexel)));
297 const quint16 shiftedU = quint16(chromaUValue << 6);
298 const quint16 shiftedV = quint16(chromaVValue << 6);
299 const char chromaTexel[4] = {
300 char(shiftedU & 0xff),
302 char(shiftedV & 0xff),
305 unsigned char *chromaBase = data + size.height() * mappedResource.RowPitch;
306 QtMultimediaTest::fillPlaneRows(chromaBase, mappedResource.RowPitch, size.width() / 2,
308 QByteArrayView(chromaTexel,
sizeof(chromaTexel)));
310 context->Unmap(stagingTexture.Get(), 0);
311 context->CopySubresourceRegion(texture.Get(), sliceSubresource(texture, arraySlice), 0, 0, 0,
312 stagingTexture.Get(), 0,
nullptr);
320 D3D11_TEXTURE2D_DESC texDesc{};
321 texDesc.Width = size.width();
322 texDesc.Height = size.height();
323 texDesc.Format = format;
324 texDesc.Usage = D3D11_USAGE_DEFAULT;
325 texDesc.CPUAccessFlags = 0;
326 texDesc.MiscFlags = 0;
327 texDesc.BindFlags = 0;
328 texDesc.ArraySize = 1;
329 texDesc.MipLevels = 1;
330 texDesc.SampleDesc = { 1, 0 };
332 ComPtr<ID3D11Texture2D> tex;
333 HRESULT hr = device->CreateTexture2D(&texDesc,
nullptr, tex.GetAddressOf());
335 qWarning() <<
"Failed to create single-plane texture" << QSystemError::windowsComString(hr);
336 return q23::unexpected{ hr };
344 QSize size, QByteArrayView texel,
345 UINT arraySlice)
const
347 const ComResult<ComPtr<ID3D11Texture2D>> staging =
348 createStagingSliceCopy(texture, arraySlice, D3D11_CPU_ACCESS_WRITE);
350 qWarning() <<
"Failed to create staging texture for single-plane fill"
351 << QSystemError::windowsComString(staging.error());
352 return staging.error();
354 const ComPtr<ID3D11Texture2D> &stagingTexture = *staging;
356 D3D11_MAPPED_SUBRESOURCE mappedResource{};
357 HRESULT hr = context->Map(stagingTexture.Get(), 0, D3D11_MAP_WRITE, 0, &mappedResource);
359 qWarning() <<
"Failed to map staging texture for single-plane fill"
360 << QSystemError::windowsComString(hr);
364 unsigned char *data =
static_cast<
unsigned char *>(mappedResource.pData);
365 QtMultimediaTest::fillPlaneRows(data, mappedResource.RowPitch, size.width(), size.height(),
368 context->Unmap(stagingTexture.Get(), 0);
369 context->CopySubresourceRegion(texture.Get(), sliceSubresource(texture, arraySlice), 0, 0, 0,
370 stagingTexture.Get(), 0,
nullptr);
377 int width,
int height,
int texelSize,
378 UINT arraySlice)
const
380 const ComResult<ComPtr<ID3D11Texture2D>> staging =
381 createStagingSliceCopy(texture, arraySlice, D3D11_CPU_ACCESS_READ);
383 qWarning() <<
"Failed to create staging texture for plane read"
384 << QSystemError::windowsComString(staging.error());
385 return q23::unexpected{ staging.error() };
387 const ComPtr<ID3D11Texture2D> &stagingTexture = *staging;
389 D3D11_MAPPED_SUBRESOURCE mappedResource{};
390 HRESULT hr = context->Map(stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mappedResource);
392 qWarning() <<
"Failed to map staging texture for plane read"
393 << QSystemError::windowsComString(hr);
394 return q23::unexpected{ hr };
397 const auto *base =
static_cast<
const unsigned char *>(mappedResource.pData);
398 const qsizetype rowBytes = qsizetype(width) * texelSize;
399 QByteArray result(rowBytes * height, Qt::Uninitialized);
400 for (
int row = 0; row < height; ++row) {
401 const unsigned char *rowData = base + (rowOffset + row) * mappedResource.RowPitch;
402 std::copy(rowData, rowData + rowBytes, result.data() + row * rowBytes);
405 context->Unmap(stagingTexture.Get(), 0);
412 const std::vector<QColor> &colors)
const
415 D3D11_TEXTURE2D_DESC desc{};
416 texture->GetDesc(&desc);
419 D3D11_TEXTURE2D_DESC stagingDesc = desc;
420 stagingDesc.Usage = D3D11_USAGE_STAGING;
421 stagingDesc.BindFlags = 0;
422 stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
423 stagingDesc.MiscFlags = 0;
425 ComPtr<ID3D11Texture2D> stagingTexture;
426 HRESULT hr = device->CreateTexture2D(&stagingDesc,
nullptr, stagingTexture.GetAddressOf());
429 qWarning() <<
"Failed to create staging texture for color fill"
430 << QSystemError::windowsComString(hr);
435 D3D11_MAPPED_SUBRESOURCE mappedResource{};
436 context->CopyResource(stagingTexture.Get(), texture.Get());
437 hr = context->Map(stagingTexture.Get(), 0, D3D11_MAP_WRITE, 0, &mappedResource);
439 qWarning() <<
"Failed to map staging texture for color fill"
440 << QSystemError::windowsComString(hr);
444 unsigned char *data =
static_cast<
unsigned char *>(mappedResource.pData);
445 for (UINT plane = 0; plane < desc.ArraySize; ++plane) {
446 const QColor color = colors[plane];
447 for (UINT row = 0; row < desc.Height; ++row) {
448 for (UINT col = 0; col < desc.Width; ++col) {
449 unsigned char *pixel = data + row * mappedResource.RowPitch
450 + plane * mappedResource.DepthPitch + col * 4;
451 pixel[0] =
static_cast<
unsigned char>(color.red());
452 pixel[1] =
static_cast<
unsigned char>(color.green());
453 pixel[2] =
static_cast<
unsigned char>(color.blue());
454 pixel[3] =
static_cast<
unsigned char>(color.alpha());
460 context->Unmap(stagingTexture.Get(), 0);
461 context->CopyResource(texture.Get(), stagingTexture.Get());
466ComResult<ComPtr<ID3D11Texture2D>>
468 UINT arraySlice, UINT cpuAccessFlags)
const
470 D3D11_TEXTURE2D_DESC stagingDesc{};
471 texture->GetDesc(&stagingDesc);
472 stagingDesc.ArraySize = 1;
473 stagingDesc.MipLevels = 1;
474 stagingDesc.Usage = D3D11_USAGE_STAGING;
475 stagingDesc.BindFlags = 0;
476 stagingDesc.CPUAccessFlags = cpuAccessFlags;
477 stagingDesc.MiscFlags = 0;
479 ComPtr<ID3D11Texture2D> stagingTexture;
480 if (
const HRESULT hr = device->CreateTexture2D(&stagingDesc,
nullptr, &stagingTexture);
482 return q23::unexpected{ hr };
485 context->CopySubresourceRegion(stagingTexture.Get(), 0, 0, 0, 0, texture.Get(),
486 sliceSubresource(texture, arraySlice),
nullptr);
487 return stagingTexture;
494 ComPtr<ID3D11Device> srcDev;
496 D3D11CreateDevice(
nullptr, driverType,
nullptr, flags,
nullptr, 0, D3D11_SDK_VERSION,
497 srcDev.GetAddressOf(),
nullptr, devContext.context.GetAddressOf());
499 qWarning() <<
"Failed to create D3D11 device" << QSystemError::windowsComString(hr);
500 return q23::unexpected{ hr };
503 hr = srcDev.As(&devContext.device);
505 qWarning() <<
"Failed to query ID3D11Device1" << QSystemError::windowsComString(hr);
506 return q23::unexpected{ hr };
517 return createD3D11TestDeviceContextImpl(D3D_DRIVER_TYPE_HARDWARE,
518 D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT
519 | D3D11_CREATE_DEVICE_VIDEO_SUPPORT);
528 return createD3D11TestDeviceContextImpl(D3D_DRIVER_TYPE_WARP, 0);
533 const auto *native =
static_cast<
const QRhiD3D11NativeHandles *>(rhi.nativeHandles());
534 if (!native || !native->dev) {
535 qWarning() <<
"Failed to wrap RHI D3D11 device: invalid native handles";
536 return q23::unexpected{ E_FAIL };
540 const ComPtr<ID3D11Device> device =
static_cast<ID3D11Device *>(native->dev);
541 HRESULT hr = device.As(&ctx.device);
543 qWarning() <<
"Failed to query ID3D11Device1 from RHI device"
544 << QSystemError::windowsComString(hr);
545 return q23::unexpected{ hr };
548 ctx.device->GetImmediateContext(ctx.context.GetAddressOf());
550 qWarning() <<
"Failed to get immediate context from RHI device";
551 return q23::unexpected{ E_FAIL };
ComResult< QWindowsD3D11TestDeviceContext > wrapRhiD3D11Device(QRhi &rhi)
ComResult< QWindowsD3D11TestDeviceContext > createD3D11TestDeviceContext()
static ComResult< QWindowsD3D11TestDeviceContext > createD3D11TestDeviceContextImpl(D3D_DRIVER_TYPE driverType, UINT flags)
ComResult< QWindowsD3D11TestDeviceContext > createWarpD3D11TestDeviceContext()
ComResult< ComPtr< ID3D11Texture2D > > createSinglePlaneTexture(QSize size, DXGI_FORMAT format) const
ComResult< ComPtr< ID3D11Texture2D > > createFilledNV12Texture(QSize size, quint8 lumaValue, quint8 chromaU, quint8 chromaV) const
ComResult< ComPtr< ID3D11Texture2D > > createNV12Texture(QSize size) const
bool isTextureFormatSupported(DXGI_FORMAT format) const
HRESULT fillNV12Texture(const ComPtr< ID3D11Texture2D > &texture, QSize size, quint8 lumaValue, quint8 chromaUValue, quint8 chromaVValue, UINT arraySlice=0) const
ComResult< QColor > getFirstPixelColorBGRA(const ComPtr< ID3D11Texture2D > &texture) const
ComResult< ComPtr< ID3D11Texture2D > > createP010Texture(QSize size) const
ComResult< QByteArray > readPlaneRows(const ComPtr< ID3D11Texture2D > &texture, int rowOffset, int width, int height, int texelSize, UINT arraySlice=0) const
HRESULT fillP010Texture(const ComPtr< ID3D11Texture2D > &texture, QSize size, quint16 lumaValue, quint16 chromaUValue, quint16 chromaVValue, UINT arraySlice=0) const
ComResult< ComPtr< ID3D11Texture2D > > createTextureArray(QSize size, const std::vector< QColor > &colors) const
HRESULT fillSinglePlaneTexture(const ComPtr< ID3D11Texture2D > &texture, QSize size, QByteArrayView texel, UINT arraySlice=0) const
ComResult< QColor > getFirstPixelColor(const ComPtr< ID3D11Texture2D > &texture) const