Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Laszlo Agocs
qtrhi
Commits
72a476b3
Commit
72a476b3
authored
Nov 27, 2018
by
Laszlo Agocs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
d3d: implement readback
parent
c4e5c4db
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
247 additions
and
103 deletions
+247
-103
src/rhi/qrhid3d11.cpp
src/rhi/qrhid3d11.cpp
+218
-97
src/rhi/qrhid3d11_p.h
src/rhi/qrhid3d11_p.h
+20
-2
src/rhi/qrhivulkan.cpp
src/rhi/qrhivulkan.cpp
+4
-0
todo.txt
todo.txt
+5
-4
No files found.
src/rhi/qrhid3d11.cpp
View file @
72a476b3
...
...
@@ -460,6 +460,7 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain)
inFrame
=
true
;
QD3D11SwapChain
*
swapChainD
=
QRHI_RES
(
QD3D11SwapChain
,
swapChain
);
contextState
.
currentSwapChain
=
swapChainD
;
swapChainD
->
cb
.
resetState
();
swapChainD
->
rt
.
d
.
pixelSize
=
swapChainD
->
pixelSize
;
...
...
@@ -492,6 +493,7 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain)
swapChainD
->
currentFrame
=
(
swapChainD
->
currentFrame
+
1
)
%
QD3D11SwapChain
::
BUFFER_COUNT
;
contextState
.
currentSwapChain
=
nullptr
;
++
finishedFrameCount
;
return
QRhi
::
FrameOpSuccess
;
}
...
...
@@ -515,27 +517,191 @@ QRhi::FrameOpResult QRhiD3D11::endOffscreenFrame()
ofr
.
active
=
false
;
executeCommandBuffer
(
&
ofr
.
cbWrapper
);
context
->
Flush
();
++
finishedFrameCount
;
return
QRhi
::
FrameOpSuccess
;;
}
bool
QRhiD3D11
::
readback
(
QRhiCommandBuffer
*
cb
,
const
QRhiReadbackDescription
&
rb
,
QRhiReadbackResult
*
result
)
static
inline
DXGI_FORMAT
toD3DTextureFormat
(
QRhiTexture
::
Format
format
,
QRhiTexture
::
Flags
flags
)
{
const
bool
srgb
=
flags
.
testFlag
(
QRhiTexture
::
sRGB
);
switch
(
format
)
{
case
QRhiTexture
::
RGBA8
:
return
srgb
?
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
:
DXGI_FORMAT_R8G8B8A8_UNORM
;
case
QRhiTexture
::
BGRA8
:
return
srgb
?
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
:
DXGI_FORMAT_B8G8R8A8_UNORM
;
case
QRhiTexture
::
R8
:
return
DXGI_FORMAT_R8_UNORM
;
case
QRhiTexture
::
R16
:
return
DXGI_FORMAT_R16_UNORM
;
case
QRhiTexture
::
D16
:
return
DXGI_FORMAT_R16_TYPELESS
;
case
QRhiTexture
::
D32
:
return
DXGI_FORMAT_R32_TYPELESS
;
case
QRhiTexture
::
BC1
:
return
srgb
?
DXGI_FORMAT_BC1_UNORM_SRGB
:
DXGI_FORMAT_BC1_UNORM
;
case
QRhiTexture
::
BC2
:
return
srgb
?
DXGI_FORMAT_BC2_UNORM_SRGB
:
DXGI_FORMAT_BC2_UNORM
;
case
QRhiTexture
::
BC3
:
return
srgb
?
DXGI_FORMAT_BC3_UNORM_SRGB
:
DXGI_FORMAT_BC3_UNORM
;
case
QRhiTexture
::
BC4
:
return
DXGI_FORMAT_BC4_UNORM
;
case
QRhiTexture
::
BC5
:
return
DXGI_FORMAT_BC5_UNORM
;
case
QRhiTexture
::
BC6H
:
return
DXGI_FORMAT_BC6H_UF16
;
case
QRhiTexture
::
BC7
:
return
srgb
?
DXGI_FORMAT_BC7_UNORM_SRGB
:
DXGI_FORMAT_BC7_UNORM
;
case
QRhiTexture
::
ETC2_RGB8
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ETC2_RGB8A1
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ETC2_RGBA8
:
qWarning
(
"QRhiD3D11 does not support ETC2 textures"
);
return
DXGI_FORMAT_R8G8B8A8_UNORM
;
case
QRhiTexture
::
ASTC_4x4
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_5x4
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_5x5
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_6x5
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_6x6
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_8x5
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_8x6
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_8x8
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_10x5
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_10x6
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_10x8
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_10x10
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_12x10
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_12x12
:
qWarning
(
"QRhiD3D11 does not support ASTC textures"
);
return
DXGI_FORMAT_R8G8B8A8_UNORM
;
default:
Q_UNREACHABLE
();
return
DXGI_FORMAT_R8G8B8A8_UNORM
;
}
}
static
inline
QRhiTexture
::
Format
colorTextureFormatFromDxgiFormat
(
DXGI_FORMAT
format
,
QRhiTexture
::
Flags
*
flags
)
{
Q_UNUSED
(
cb
);
Q_UNUSED
(
rb
);
Q_UNUSED
(
result
);
switch
(
format
)
{
case
DXGI_FORMAT_R8G8B8A8_UNORM
:
return
QRhiTexture
::
RGBA8
;
case
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
:
if
(
flags
)
(
*
flags
)
|=
QRhiTexture
::
sRGB
;
return
QRhiTexture
::
RGBA8
;
case
DXGI_FORMAT_B8G8R8A8_UNORM
:
return
QRhiTexture
::
BGRA8
;
case
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
:
if
(
flags
)
(
*
flags
)
|=
QRhiTexture
::
sRGB
;
return
QRhiTexture
::
BGRA8
;
case
DXGI_FORMAT_R8_UNORM
:
return
QRhiTexture
::
R8
;
case
DXGI_FORMAT_R16_UNORM
:
return
QRhiTexture
::
R16
;
default:
// this cannot assert, must warn and return unknown
qWarning
(
"DXGI_FORMAT %d is not a recognized uncompressed color format"
,
format
);
break
;
}
return
QRhiTexture
::
UnknownFormat
;
}
static
inline
bool
isDepthTextureFormat
(
QRhiTexture
::
Format
format
)
{
switch
(
format
)
{
case
QRhiTexture
::
Format
::
D16
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
Format
::
D32
:
return
true
;
default:
return
false
;
}
}
bool
QRhiD3D11
::
readback
(
QRhiCommandBuffer
*
cb
,
const
QRhiReadbackDescription
&
rb
,
QRhiReadbackResult
*
result
)
{
Q_ASSERT
(
inFrame
&&
!
inPass
);
ID3D11Resource
*
src
;
DXGI_FORMAT
dxgiFormat
;
QSize
pixelSize
;
QRhiTexture
::
Format
format
;
UINT
subres
=
0
;
QD3D11Texture
*
texD
=
QRHI_RES
(
QD3D11Texture
,
rb
.
texture
);
QD3D11SwapChain
*
swapChainD
=
nullptr
;
if
(
texD
)
{
src
=
texD
->
tex
;
dxgiFormat
=
toD3DTextureFormat
(
texD
->
m_format
,
texD
->
m_flags
);
pixelSize
=
texD
->
m_pixelSize
;
if
(
rb
.
level
>
0
)
{
pixelSize
.
setWidth
(
qFloor
(
float
(
qMax
(
1
,
pixelSize
.
width
()
>>
rb
.
level
))));
pixelSize
.
setHeight
(
qFloor
(
float
(
qMax
(
1
,
pixelSize
.
height
()
>>
rb
.
level
))));
}
format
=
texD
->
m_format
;
subres
=
D3D11CalcSubresource
(
rb
.
level
,
rb
.
layer
,
texD
->
mipLevelCount
);
}
else
{
Q_ASSERT
(
contextState
.
currentSwapChain
);
swapChainD
=
QRHI_RES
(
QD3D11SwapChain
,
contextState
.
currentSwapChain
);
src
=
swapChainD
->
tex
[
swapChainD
->
currentFrame
];
dxgiFormat
=
swapChainD
->
colorFormat
;
pixelSize
=
swapChainD
->
pixelSize
;
format
=
colorTextureFormatFromDxgiFormat
(
dxgiFormat
,
nullptr
);
if
(
format
==
QRhiTexture
::
UnknownFormat
)
return
false
;
}
quint32
bufSize
=
0
;
textureFormatInfo
(
format
,
pixelSize
,
nullptr
,
&
bufSize
);
QD3D11CommandBuffer
*
cbD
=
QRHI_RES
(
QD3D11CommandBuffer
,
cb
);
QD3D11CommandBuffer
::
Command
cmd
;
cmd
.
cmd
=
QD3D11CommandBuffer
::
Command
::
ReadPixels
;
cmd
.
args
.
readPixels
.
src
=
src
;
cmd
.
args
.
readPixels
.
dxgiFormat
=
dxgiFormat
;
cmd
.
args
.
readPixels
.
format
=
format
;
cmd
.
args
.
readPixels
.
w
=
pixelSize
.
width
();
cmd
.
args
.
readPixels
.
h
=
pixelSize
.
height
();
cmd
.
args
.
readPixels
.
byteSize
=
bufSize
;
cmd
.
args
.
readPixels
.
subres
=
subres
;
cmd
.
args
.
readPixels
.
result
=
result
;
cbD
->
commands
.
append
(
cmd
);
return
true
;
}
QRhi
::
FrameOpResult
QRhiD3D11
::
finish
()
{
Q_ASSERT
(
!
inPass
);
context
->
Flush
();
if
(
inFrame
)
{
if
(
ofr
.
active
)
{
Q_ASSERT
(
!
contextState
.
currentSwapChain
);
executeCommandBuffer
(
&
ofr
.
cbWrapper
);
ofr
.
cbWrapper
.
resetCommands
();
}
else
{
Q_ASSERT
(
contextState
.
currentSwapChain
);
executeCommandBuffer
(
&
contextState
.
currentSwapChain
->
cb
);
contextState
.
currentSwapChain
->
cb
.
resetCommands
();
}
}
return
QRhi
::
FrameOpSuccess
;
}
...
...
@@ -928,12 +1094,57 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
qWarning
(
"No graphics pipeline active for drawIndexed; ignored"
);
}
break
;
case
QD3D11CommandBuffer
::
Command
::
ReadPixels
:
readPixels
(
cmd
);
break
;
default:
break
;
}
}
}
void
QRhiD3D11
::
readPixels
(
const
QD3D11CommandBuffer
::
Command
&
cmd
)
{
D3D11_TEXTURE2D_DESC
desc
;
memset
(
&
desc
,
0
,
sizeof
(
desc
));
desc
.
Width
=
cmd
.
args
.
readPixels
.
w
;
desc
.
Height
=
cmd
.
args
.
readPixels
.
h
;
desc
.
MipLevels
=
1
;
desc
.
ArraySize
=
1
;
desc
.
Format
=
cmd
.
args
.
readPixels
.
dxgiFormat
;
desc
.
SampleDesc
.
Count
=
1
;
desc
.
Usage
=
D3D11_USAGE_STAGING
;
desc
.
CPUAccessFlags
=
D3D11_CPU_ACCESS_READ
;
ID3D11Texture2D
*
stagingTex
;
HRESULT
hr
=
dev
->
CreateTexture2D
(
&
desc
,
nullptr
,
&
stagingTex
);
if
(
FAILED
(
hr
))
{
qWarning
(
"Failed to create readback staging texture: %s"
,
qPrintable
(
comErrorMessage
(
hr
)));
return
;
}
context
->
CopySubresourceRegion
(
stagingTex
,
0
,
0
,
0
,
0
,
cmd
.
args
.
readPixels
.
src
,
cmd
.
args
.
readPixels
.
subres
,
nullptr
);
D3D11_MAPPED_SUBRESOURCE
mp
;
hr
=
context
->
Map
(
stagingTex
,
0
,
D3D11_MAP_READ
,
0
,
&
mp
);
if
(
FAILED
(
hr
))
{
qWarning
(
"Failed to map readback staging texture: %s"
,
qPrintable
(
comErrorMessage
(
hr
)));
stagingTex
->
Release
();
return
;
}
QRhiReadbackResult
*
result
=
cmd
.
args
.
readPixels
.
result
;
result
->
format
=
cmd
.
args
.
readPixels
.
format
;
result
->
pixelSize
=
QSize
(
cmd
.
args
.
readPixels
.
w
,
cmd
.
args
.
readPixels
.
h
);
result
->
data
.
resize
(
cmd
.
args
.
readPixels
.
byteSize
);
memcpy
(
result
->
data
.
data
(),
mp
.
pData
,
result
->
data
.
size
());
context
->
Unmap
(
stagingTex
,
0
);
stagingTex
->
Release
();
if
(
result
->
completed
)
result
->
completed
();
}
QD3D11Buffer
::
QD3D11Buffer
(
QRhiImplementation
*
rhi
,
Type
type
,
UsageFlags
usage
,
int
size
)
:
QRhiBuffer
(
rhi
,
type
,
usage
,
size
)
{
...
...
@@ -1067,96 +1278,6 @@ void QD3D11Texture::release()
tex
=
nullptr
;
}
static
inline
DXGI_FORMAT
toD3DTextureFormat
(
QRhiTexture
::
Format
format
,
QRhiTexture
::
Flags
flags
)
{
const
bool
srgb
=
flags
.
testFlag
(
QRhiTexture
::
sRGB
);
switch
(
format
)
{
case
QRhiTexture
::
RGBA8
:
return
srgb
?
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
:
DXGI_FORMAT_R8G8B8A8_UNORM
;
case
QRhiTexture
::
BGRA8
:
return
srgb
?
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB
:
DXGI_FORMAT_B8G8R8A8_UNORM
;
case
QRhiTexture
::
R8
:
return
DXGI_FORMAT_R8_UNORM
;
case
QRhiTexture
::
R16
:
return
DXGI_FORMAT_R16_UNORM
;
case
QRhiTexture
::
D16
:
return
DXGI_FORMAT_R16_TYPELESS
;
case
QRhiTexture
::
D32
:
return
DXGI_FORMAT_R32_TYPELESS
;
case
QRhiTexture
::
BC1
:
return
srgb
?
DXGI_FORMAT_BC1_UNORM_SRGB
:
DXGI_FORMAT_BC1_UNORM
;
case
QRhiTexture
::
BC2
:
return
srgb
?
DXGI_FORMAT_BC2_UNORM_SRGB
:
DXGI_FORMAT_BC2_UNORM
;
case
QRhiTexture
::
BC3
:
return
srgb
?
DXGI_FORMAT_BC3_UNORM_SRGB
:
DXGI_FORMAT_BC3_UNORM
;
case
QRhiTexture
::
BC4
:
return
DXGI_FORMAT_BC4_UNORM
;
case
QRhiTexture
::
BC5
:
return
DXGI_FORMAT_BC5_UNORM
;
case
QRhiTexture
::
BC6H
:
return
DXGI_FORMAT_BC6H_UF16
;
case
QRhiTexture
::
BC7
:
return
srgb
?
DXGI_FORMAT_BC7_UNORM_SRGB
:
DXGI_FORMAT_BC7_UNORM
;
case
QRhiTexture
::
ETC2_RGB8
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ETC2_RGB8A1
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ETC2_RGBA8
:
qWarning
(
"QRhiD3D11 does not support ETC2 textures"
);
return
DXGI_FORMAT_R8G8B8A8_UNORM
;
case
QRhiTexture
::
ASTC_4x4
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_5x4
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_5x5
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_6x5
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_6x6
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_8x5
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_8x6
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_8x8
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_10x5
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_10x6
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_10x8
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_10x10
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_12x10
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
ASTC_12x12
:
qWarning
(
"QRhiD3D11 does not support ASTC textures"
);
return
DXGI_FORMAT_R8G8B8A8_UNORM
;
default:
Q_UNREACHABLE
();
return
DXGI_FORMAT_R8G8B8A8_UNORM
;
}
}
static
inline
bool
isDepthTextureFormat
(
QRhiTexture
::
Format
format
)
{
switch
(
format
)
{
case
QRhiTexture
::
Format
::
D16
:
Q_FALLTHROUGH
();
case
QRhiTexture
::
Format
::
D32
:
return
true
;
default:
return
false
;
}
}
static
inline
DXGI_FORMAT
toD3DDepthTextureSRVFormat
(
QRhiTexture
::
Format
format
)
{
switch
(
format
)
{
...
...
src/rhi/qrhid3d11_p.h
View file @
72a476b3
...
...
@@ -219,6 +219,9 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
QD3D11CommandBuffer
(
QRhiImplementation
*
rhi
);
void
release
()
override
;
// Technically it's not like we really need to queue up the commands, but
// have it this way since it helps keeping things concise and may become
// essential if "command buffers" become application creatable some day.
struct
Command
{
enum
Cmd
{
SetRenderTarget
,
...
...
@@ -231,7 +234,8 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
StencilRef
,
BlendConstants
,
Draw
,
DrawIndexed
DrawIndexed
,
ReadPixels
};
enum
ClearFlag
{
Color
=
1
,
Depth
=
2
,
Stencil
=
4
};
Cmd
cmd
;
...
...
@@ -293,6 +297,16 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
qint32
vertexOffset
;
quint32
firstInstance
;
}
drawIndexed
;
struct
{
ID3D11Resource
*
src
;
QRhiTexture
::
Format
format
;
DXGI_FORMAT
dxgiFormat
;
int
w
;
int
h
;
quint32
byteSize
;
UINT
subres
;
QRhiReadbackResult
*
result
;
}
readPixels
;
}
args
;
};
...
...
@@ -303,8 +317,11 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
QRhiShaderResourceBindings
*
currentSrb
;
uint
currentSrbGeneration
;
void
reset
State
()
{
void
reset
Commands
()
{
commands
.
clear
();
}
void
resetState
()
{
resetCommands
();
currentTarget
=
nullptr
;
currentPipeline
=
nullptr
;
currentPipelineGeneration
=
0
;
...
...
@@ -420,6 +437,7 @@ public:
void
executeBufferHostWritesForCurrentFrame
(
QD3D11Buffer
*
bufD
);
void
setShaderResources
(
QD3D11ShaderResourceBindings
*
srbD
);
void
executeCommandBuffer
(
QD3D11CommandBuffer
*
cbD
);
void
readPixels
(
const
QD3D11CommandBuffer
::
Command
&
cmd
);
DXGI_SAMPLE_DESC
effectiveSampleCount
(
int
sampleCount
)
const
;
bool
debugLayer
=
false
;
...
...
src/rhi/qrhivulkan.cpp
View file @
72a476b3
...
...
@@ -1448,6 +1448,10 @@ bool QRhiVulkan::readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &
QVkSwapChain
*
swapChainD
=
nullptr
;
if
(
texD
)
{
aRb
.
pixelSize
=
texD
->
m_pixelSize
;
if
(
rb
.
level
>
0
)
{
aRb
.
pixelSize
.
setWidth
(
qFloor
(
float
(
qMax
(
1
,
aRb
.
pixelSize
.
width
()
>>
rb
.
level
))));
aRb
.
pixelSize
.
setHeight
(
qFloor
(
float
(
qMax
(
1
,
aRb
.
pixelSize
.
height
()
>>
rb
.
level
))));
}
aRb
.
format
=
texD
->
m_format
;
}
else
{
Q_ASSERT
(
currentSwapChain
);
...
...
todo.txt
View file @
72a476b3
mtl, d3d, gl: readback (tex, backbuffer)
mtl, d3d, gl: implement finish()
mtl, gl: rhi without a window
gl, mtl: rhi without a window, offscreen frame
gl, mtl: readback (tex, backbuffer)
gl, mtl: compressed textures
gl, mtl: srgb (tex, swapchain buf)
multi window? (multi swapchain) -> trouble
...
...
@@ -15,7 +14,8 @@ cbuffer alignment rules - some things fail to translate (to hlsl e.g. with struc
resource import/export, what's the co-op story?
copy-only passes for kicking off transfers early? (copy/transfer queue?)
copyimage (color and ds, no resolve or transforms here)
msaa offscreen (msaa texture? renderbuffer?)
does reading back an msaa swapchain buffer work?
msaa offscreen (msaa texture. no readback.)
resolveimage (color and ds, only to resolve samples)
threading options? secondary command lists?
mipmap generation?
...
...
@@ -50,6 +50,7 @@ dxc for d3d as an alternative to fxc?
hlsl -> dxc -> spirv -> spirv-cross hmmm...
+++ done
d3d: readback
d3d: offscreen frame
vk: read back the backbuffer
vk: readback size/formats
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment