зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1600595: Part 3 - Add D3D11 utilities for creating CPU textures and converting format enums r=jrmuizel
CreateBGRA8DataSourceSurfaceForD3D11Texture is added to create a CPU texture with the same data as the given D3D11 texture. ReadbackTexture reads a D3D11 texture into a pre-existing CPU texture. ToPixelFormat is extended to cover DXGI_FORMAT values. Differential Revision: https://phabricator.services.mozilla.com/D57562 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
c8478e9ba2
Коммит
83cbdc257d
23
gfx/2d/2D.h
23
gfx/2d/2D.h
|
@ -83,6 +83,10 @@ namespace mozilla {
|
|||
|
||||
class Mutex;
|
||||
|
||||
namespace layers {
|
||||
class TextureData;
|
||||
}
|
||||
|
||||
namespace wr {
|
||||
struct FontInstanceOptions;
|
||||
struct FontInstancePlatformOptions;
|
||||
|
@ -1901,6 +1905,15 @@ class GFX2D_API Factory {
|
|||
|
||||
static void SetSystemTextQuality(uint8_t aQuality);
|
||||
|
||||
static already_AddRefed<DataSourceSurface>
|
||||
CreateBGRA8DataSourceSurfaceForD3D11Texture(ID3D11Texture2D* aSrcTexture);
|
||||
|
||||
static bool ReadbackTexture(layers::TextureData* aDestCpuTexture,
|
||||
ID3D11Texture2D* aSrcTexture);
|
||||
|
||||
static bool ReadbackTexture(DataSourceSurface* aDestCpuTexture,
|
||||
ID3D11Texture2D* aSrcTexture);
|
||||
|
||||
private:
|
||||
static StaticRefPtr<ID2D1Device> mD2D1Device;
|
||||
static StaticRefPtr<ID3D11Device> mD3D11Device;
|
||||
|
@ -1910,6 +1923,14 @@ class GFX2D_API Factory {
|
|||
static StaticRefPtr<ID2D1DeviceContext> mMTDC;
|
||||
static StaticRefPtr<ID2D1DeviceContext> mOffMTDC;
|
||||
|
||||
static bool ReadbackTexture(uint8_t* aDestData, int32_t aDestStride,
|
||||
ID3D11Texture2D* aSrcTexture);
|
||||
|
||||
// DestTextureT can be TextureData or DataSourceSurface.
|
||||
template <typename DestTextureT>
|
||||
static bool ConvertSourceAndRetryReadback(DestTextureT* aDestCpuTexture,
|
||||
ID3D11Texture2D* aSrcTexture);
|
||||
|
||||
protected:
|
||||
// This guards access to the singleton devices above, as well as the
|
||||
// singleton devices in DrawTargetD2D1.
|
||||
|
@ -1919,7 +1940,7 @@ class GFX2D_API Factory {
|
|||
static StaticMutex mDTDependencyLock;
|
||||
|
||||
friend class DrawTargetD2D1;
|
||||
#endif
|
||||
#endif // WIN32
|
||||
|
||||
private:
|
||||
static DrawEventRecorder* mRecorder;
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
# include "NativeFontResourceDWrite.h"
|
||||
# include <d3d10_1.h>
|
||||
# include "HelpersD2D.h"
|
||||
# include "DXVA2Manager.h"
|
||||
# include "mozilla/layers/TextureD3D11.h"
|
||||
#endif
|
||||
|
||||
#include "DrawTargetCapture.h"
|
||||
|
@ -62,6 +64,8 @@
|
|||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
|
||||
#ifdef MOZ_ENABLE_FREETYPE
|
||||
# include "ft2build.h"
|
||||
# include FT_FREETYPE_H
|
||||
|
@ -1161,6 +1165,191 @@ void Factory::SetGlobalEventRecorder(DrawEventRecorder* aRecorder) {
|
|||
mRecorder = aRecorder;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/* static */
|
||||
already_AddRefed<DataSourceSurface>
|
||||
Factory::CreateBGRA8DataSourceSurfaceForD3D11Texture(
|
||||
ID3D11Texture2D* aSrcTexture) {
|
||||
D3D11_TEXTURE2D_DESC srcDesc = {0};
|
||||
aSrcTexture->GetDesc(&srcDesc);
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> destTexture =
|
||||
gfx::Factory::CreateDataSourceSurface(
|
||||
IntSize(srcDesc.Width, srcDesc.Height), gfx::SurfaceFormat::B8G8R8A8);
|
||||
if (NS_WARN_IF(!destTexture)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!ReadbackTexture(destTexture, aSrcTexture)) {
|
||||
return nullptr;
|
||||
}
|
||||
return destTexture.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
template <typename DestTextureT>
|
||||
bool Factory::ConvertSourceAndRetryReadback(DestTextureT* aDestCpuTexture,
|
||||
ID3D11Texture2D* aSrcTexture) {
|
||||
RefPtr<ID3D11Device> device;
|
||||
aSrcTexture->GetDevice(getter_AddRefs(device));
|
||||
if (!device) {
|
||||
gfxWarning() << "Failed to get D3D11 device from source texture";
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString error;
|
||||
std::unique_ptr<DXVA2Manager> manager(
|
||||
DXVA2Manager::CreateD3D11DXVA(nullptr, error, device));
|
||||
if (!manager) {
|
||||
gfxWarning() << "Failed to create DXVA2 manager!";
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11Texture2D> newSrcTexture;
|
||||
HRESULT hr =
|
||||
manager->CopyToBGRATexture(aSrcTexture, getter_AddRefs(newSrcTexture));
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Failed to copy to BGRA texture.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return ReadbackTexture(aDestCpuTexture, newSrcTexture);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool Factory::ReadbackTexture(layers::TextureData* aDestCpuTexture,
|
||||
ID3D11Texture2D* aSrcTexture) {
|
||||
layers::MappedTextureData mappedData;
|
||||
if (!aDestCpuTexture->BorrowMappedData(mappedData)) {
|
||||
gfxWarning() << "Could not access in-memory texture";
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC srcDesc = {0};
|
||||
aSrcTexture->GetDesc(&srcDesc);
|
||||
|
||||
// Special case: If the source and destination have different formats and the
|
||||
// destination is B8G8R8A8 then convert the source to B8G8R8A8 and readback.
|
||||
if ((srcDesc.Format != DXGIFormat(mappedData.format)) &&
|
||||
(mappedData.format == SurfaceFormat::B8G8R8A8)) {
|
||||
return ConvertSourceAndRetryReadback(aDestCpuTexture, aSrcTexture);
|
||||
}
|
||||
|
||||
if ((IntSize(srcDesc.Width, srcDesc.Height) != mappedData.size) ||
|
||||
(srcDesc.Format != DXGIFormat(mappedData.format))) {
|
||||
gfxWarning() << "Attempted readback between incompatible textures";
|
||||
return false;
|
||||
}
|
||||
|
||||
return ReadbackTexture(mappedData.data, mappedData.stride, aSrcTexture);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool Factory::ReadbackTexture(DataSourceSurface* aDestCpuTexture,
|
||||
ID3D11Texture2D* aSrcTexture) {
|
||||
D3D11_TEXTURE2D_DESC srcDesc = {0};
|
||||
aSrcTexture->GetDesc(&srcDesc);
|
||||
|
||||
// Special case: If the source and destination have different formats and the
|
||||
// destination is B8G8R8A8 then convert the source to B8G8R8A8 and readback.
|
||||
if ((srcDesc.Format != DXGIFormat(aDestCpuTexture->GetFormat())) &&
|
||||
(aDestCpuTexture->GetFormat() == SurfaceFormat::B8G8R8A8)) {
|
||||
return ConvertSourceAndRetryReadback(aDestCpuTexture, aSrcTexture);
|
||||
}
|
||||
|
||||
if ((IntSize(srcDesc.Width, srcDesc.Height) != aDestCpuTexture->GetSize()) ||
|
||||
(srcDesc.Format != DXGIFormat(aDestCpuTexture->GetFormat()))) {
|
||||
gfxWarning() << "Attempted readback between incompatible textures";
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::DataSourceSurface::MappedSurface mappedSurface;
|
||||
if (!aDestCpuTexture->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret =
|
||||
ReadbackTexture(mappedSurface.mData, mappedSurface.mStride, aSrcTexture);
|
||||
aDestCpuTexture->Unmap();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool Factory::ReadbackTexture(uint8_t* aDestData, int32_t aDestStride,
|
||||
ID3D11Texture2D* aSrcTexture) {
|
||||
MOZ_ASSERT(aDestData && aDestStride && aSrcTexture);
|
||||
|
||||
RefPtr<ID3D11Device> device;
|
||||
aSrcTexture->GetDevice(getter_AddRefs(device));
|
||||
if (!device) {
|
||||
gfxWarning() << "Failed to get D3D11 device from source texture";
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ID3D11DeviceContext> context;
|
||||
device->GetImmediateContext(getter_AddRefs(context));
|
||||
if (!context) {
|
||||
gfxWarning() << "Could not get an immediate D3D11 context";
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<IDXGIKeyedMutex> mutex;
|
||||
HRESULT hr = aSrcTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
|
||||
(void**)getter_AddRefs(mutex));
|
||||
if (SUCCEEDED(hr) && mutex) {
|
||||
hr = mutex->AcquireSync(0, 2000);
|
||||
if (hr != S_OK) {
|
||||
gfxWarning() << "Could not acquire DXGI surface lock in 2 seconds";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC srcDesc = {0};
|
||||
aSrcTexture->GetDesc(&srcDesc);
|
||||
srcDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
srcDesc.Usage = D3D11_USAGE_STAGING;
|
||||
srcDesc.BindFlags = 0;
|
||||
srcDesc.MiscFlags = 0;
|
||||
srcDesc.MipLevels = 1;
|
||||
RefPtr<ID3D11Texture2D> srcCpuTexture;
|
||||
hr =
|
||||
device->CreateTexture2D(&srcDesc, nullptr, getter_AddRefs(srcCpuTexture));
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Could not create source texture for mapping";
|
||||
if (mutex) {
|
||||
mutex->ReleaseSync(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
context->CopyResource(srcCpuTexture, aSrcTexture);
|
||||
|
||||
if (mutex) {
|
||||
mutex->ReleaseSync(0);
|
||||
mutex = nullptr;
|
||||
}
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE srcMap;
|
||||
hr = context->Map(srcCpuTexture, 0, D3D11_MAP_READ, 0, &srcMap);
|
||||
if (FAILED(hr)) {
|
||||
gfxWarning() << "Could not map source texture";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t width = srcDesc.Width;
|
||||
uint32_t height = srcDesc.Height;
|
||||
int bpp = BytesPerPixel(gfx::ToPixelFormat(srcDesc.Format));
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(aDestData + aDestStride * y,
|
||||
(unsigned char*)(srcMap.pData) + srcMap.RowPitch * y, width * bpp);
|
||||
}
|
||||
|
||||
context->Unmap(srcCpuTexture, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
// static
|
||||
void CriticalLogger::OutputMessage(const std::string& aString, int aLevel,
|
||||
bool aNoNewline) {
|
||||
|
|
|
@ -126,6 +126,16 @@ static inline IntSize ToIntSize(const D2D1_SIZE_U& aSize) {
|
|||
return IntSize(aSize.width, aSize.height);
|
||||
}
|
||||
|
||||
static inline SurfaceFormat ToPixelFormat(const DXGI_FORMAT& aFormat) {
|
||||
switch (aFormat) {
|
||||
case DXGI_FORMAT_A8_UNORM:
|
||||
case DXGI_FORMAT_R8_UNORM:
|
||||
return SurfaceFormat::A8;
|
||||
default:
|
||||
return SurfaceFormat::B8G8R8A8;
|
||||
}
|
||||
}
|
||||
|
||||
static inline SurfaceFormat ToPixelFormat(const D2D1_PIXEL_FORMAT& aFormat) {
|
||||
switch (aFormat.format) {
|
||||
case DXGI_FORMAT_A8_UNORM:
|
||||
|
|
Загрузка…
Ссылка в новой задаче