diff options
author | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2016-03-21 11:24:03 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2016-03-22 09:51:50 +0000 |
commit | e32fb877ec0662dfda41ce490d77d8bf35a377f1 (patch) | |
tree | 64a05c1a2a37a0b27f0d92597d45643e75769965 | |
parent | 83eee56e9c047ff83329fe4a175a4b40fdbcb5d2 (diff) |
D3D12: Support offscreen render targets in the engine
Also add a skeleton for the QSGLayer implementation.
Change-Id: Id7234fa48b5c243147009a23d0e9689894a18366
Reviewed-by: Andy Nichols <andy.nichols@theqtcompany.com>
10 files changed, 599 insertions, 85 deletions
diff --git a/src/quick/scenegraph/adaptations/d3d12/d3d12.pri b/src/quick/scenegraph/adaptations/d3d12/d3d12.pri index 8950734c56..1a24f84756 100644 --- a/src/quick/scenegraph/adaptations/d3d12/d3d12.pri +++ b/src/quick/scenegraph/adaptations/d3d12/d3d12.pri @@ -10,7 +10,8 @@ SOURCES += \ $$PWD/qsgd3d12texture.cpp \ $$PWD/qsgd3d12imagenode.cpp \ $$PWD/qsgd3d12glyphnode.cpp \ - $$PWD/qsgd3d12glyphcache.cpp + $$PWD/qsgd3d12glyphcache.cpp \ + $$PWD/qsgd3d12layer.cpp NO_PCH_SOURCES += \ $$PWD/qsgd3d12engine.cpp @@ -29,7 +30,8 @@ HEADERS += \ $$PWD/qsgd3d12texture_p.h \ $$PWD/qsgd3d12imagenode_p.h \ $$PWD/qsgd3d12glyphnode_p.h \ - $$PWD/qsgd3d12glyphcache_p.h + $$PWD/qsgd3d12glyphcache_p.h \ + $$PWD/qsgd3d12layer_p.h LIBS += -ldxgi -ld3d12 diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context.cpp index f54be683f5..5c0d739c01 100644 --- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context.cpp +++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context.cpp @@ -88,6 +88,11 @@ QSGLayer *QSGD3D12Context::createLayer(QSGRenderContext *rc) return nullptr; } +QSize QSGD3D12Context::minimumFBOSize() const +{ + return QSize(16, 16); +} + QSurfaceFormat QSGD3D12Context::defaultSurfaceFormat() const { return QSGContext::defaultSurfaceFormat(); diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context_p.h index 6a092e8606..2afe22e3af 100644 --- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context_p.h +++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12context_p.h @@ -67,6 +67,7 @@ public: QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) override; QSGNinePatchNode *createNinePatchNode() override; QSGLayer *createLayer(QSGRenderContext *rc) override; + QSize minimumFBOSize() const override; QSurfaceFormat defaultSurfaceFormat() const override; }; diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp index f0ac2eee15..c486b0bfdd 100644 --- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp +++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine.cpp @@ -376,9 +376,9 @@ void QSGD3D12Engine::queueScissor(const QRect &rect) d->queueScissor(rect); } -void QSGD3D12Engine::queueSetRenderTarget() +void QSGD3D12Engine::queueSetRenderTarget(uint id) { - d->queueSetRenderTarget(); + d->queueSetRenderTarget(id); } void QSGD3D12Engine::queueClearRenderTarget(const QColor &color) @@ -458,6 +458,26 @@ void QSGD3D12Engine::activateTexture(uint id) d->activateTexture(id); } +uint QSGD3D12Engine::genRenderTarget() +{ + return d->genRenderTarget(); +} + +void QSGD3D12Engine::createRenderTarget(uint id, const QSize &size, const QVector4D &clearColor, int samples) +{ + d->createRenderTarget(id, size, clearColor, samples); +} + +void QSGD3D12Engine::releaseRenderTarget(uint id) +{ + d->releaseRenderTarget(id); +} + +void QSGD3D12Engine::activateRenderTargetAsTexture(uint id) +{ + d->activateRenderTargetAsTexture(id); +} + static inline quint32 alignedSize(quint32 size, quint32 byteAlign) { return (size + byteAlign - 1) & ~(byteAlign - 1); @@ -564,7 +584,7 @@ void QSGD3D12EnginePrivate::releaseResources() depthStencil = nullptr; for (int i = 0; i < SWAP_CHAIN_BUFFER_COUNT; ++i) - renderTargets[i] = nullptr; + backBufferRT[i] = nullptr; for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { pframeData[i].vertex.buffer = nullptr; @@ -576,6 +596,7 @@ void QSGD3D12EnginePrivate::releaseResources() psoCache.clear(); rootSigCache.clear(); textures.clear(); + renderTargets.clear(); cpuDescHeapManager.releaseResources(); @@ -709,6 +730,8 @@ void QSGD3D12EnginePrivate::initialize(QWindow *w) if (!mipmapper.initialize(this)) return; + currentRenderTarget = 0; + initialized = true; } @@ -754,6 +777,41 @@ DXGI_SAMPLE_DESC QSGD3D12EnginePrivate::makeSampleDesc(DXGI_FORMAT format, int s return sampleDesc; } +ID3D12Resource *QSGD3D12EnginePrivate::createColorBuffer(D3D12_CPU_DESCRIPTOR_HANDLE viewHandle, const QSize &size, + const QVector4D &clearColor, int samples) +{ + D3D12_CLEAR_VALUE clearValue = {}; + clearValue.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + clearValue.Color[0] = clearColor.x(); + clearValue.Color[1] = clearColor.y(); + clearValue.Color[2] = clearColor.z(); + clearValue.Color[3] = clearColor.w(); + + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; + + D3D12_RESOURCE_DESC rtDesc = {}; + rtDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + rtDesc.Width = size.width(); + rtDesc.Height = size.height(); + rtDesc.DepthOrArraySize = 1; + rtDesc.MipLevels = 1; + rtDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + rtDesc.SampleDesc = makeSampleDesc(rtDesc.Format, samples); + rtDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + + ID3D12Resource *resource = nullptr; + if (FAILED(device->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &rtDesc, + D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue, IID_PPV_ARGS(&resource)))) { + qWarning("Failed to create offscreen render target of size %dx%d", size.width(), size.height()); + return nullptr; + } + + device->CreateRenderTargetView(resource, nullptr, viewHandle); + + return resource; +} + ID3D12Resource *QSGD3D12EnginePrivate::createDepthStencil(D3D12_CPU_DESCRIPTOR_HANDLE viewHandle, const QSize &size, int samples) { D3D12_CLEAR_VALUE depthClearValue = {}; @@ -793,17 +851,19 @@ ID3D12Resource *QSGD3D12EnginePrivate::createDepthStencil(D3D12_CPU_DESCRIPTOR_H void QSGD3D12EnginePrivate::setupRenderTargets() { + // ### multisampling needs an offscreen rt and explicit resolve, add this at some point + for (int i = 0; i < SWAP_CHAIN_BUFFER_COUNT; ++i) { - if (FAILED(swapChain->GetBuffer(i, IID_PPV_ARGS(&renderTargets[i])))) { + if (FAILED(swapChain->GetBuffer(i, IID_PPV_ARGS(&backBufferRT[i])))) { qWarning("Failed to get buffer %d from swap chain", i); return; } - rtv[i] = cpuDescHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - device->CreateRenderTargetView(renderTargets[i].Get(), nullptr, rtv[i]); + backBufferRTV[i] = cpuDescHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + device->CreateRenderTargetView(backBufferRT[i].Get(), nullptr, backBufferRTV[i]); } - dsv = cpuDescHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); - ID3D12Resource *ds = createDepthStencil(dsv, window->size(), 0); + backBufferDSV = cpuDescHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + ID3D12Resource *ds = createDepthStencil(backBufferDSV, window->size(), 0); if (ds) depthStencil.Attach(ds); @@ -820,10 +880,10 @@ void QSGD3D12EnginePrivate::resize() // Clear these, otherwise resizing will fail. depthStencil = nullptr; - cpuDescHeapManager.release(dsv, D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + cpuDescHeapManager.release(backBufferDSV, D3D12_DESCRIPTOR_HEAP_TYPE_DSV); for (int i = 0; i < SWAP_CHAIN_BUFFER_COUNT; ++i) { - renderTargets[i] = nullptr; - cpuDescHeapManager.release(rtv[i], D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + backBufferRT[i] = nullptr; + cpuDescHeapManager.release(backBufferRTV[i], D3D12_DESCRIPTOR_HEAP_TYPE_RTV); } HRESULT hr = swapChain->ResizeBuffers(SWAP_CHAIN_BUFFER_COUNT, window->width(), window->height(), DXGI_FORMAT_R8G8B8A8_UNORM, 0); @@ -923,14 +983,14 @@ ID3D12Resource *QSGD3D12EnginePrivate::createBuffer(int size) return buf; } -ID3D12Resource *QSGD3D12EnginePrivate::backBufferRT() const +ID3D12Resource *QSGD3D12EnginePrivate::currentBackBufferRT() const { - return renderTargets[presentFrameIndex % SWAP_CHAIN_BUFFER_COUNT].Get(); + return backBufferRT[presentFrameIndex % SWAP_CHAIN_BUFFER_COUNT].Get(); } -D3D12_CPU_DESCRIPTOR_HANDLE QSGD3D12EnginePrivate::backBufferRTV() const +D3D12_CPU_DESCRIPTOR_HANDLE QSGD3D12EnginePrivate::currentBackBufferRTV() const { - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtv[0]; + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = backBufferRTV[0]; rtvHandle.ptr += (presentFrameIndex % SWAP_CHAIN_BUFFER_COUNT) * cpuDescHeapManager.handleSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); return rtvHandle; } @@ -1125,7 +1185,7 @@ void QSGD3D12EnginePrivate::beginFrame() if (!pfd.pendingTextureReleases.isEmpty()) { for (uint id : qAsConst(pfd.pendingTextureReleases)) { Texture &t(textures[id - 1]); - t.entryInUse = false; // createTexture() can now reuse this entry + t.flags &= ~RenderTarget::EntryInUse; // createTexture() can now reuse this entry t.texture = nullptr; } pfd.pendingTextureReleases.clear(); @@ -1151,7 +1211,7 @@ void QSGD3D12EnginePrivate::beginDrawCalls(bool needsBackbufferTransition) tframeData.descHeapSet = false; if (needsBackbufferTransition) - transitionResource(backBufferRT(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); + transitionResource(currentBackBufferRT(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); } void QSGD3D12EnginePrivate::endFrame() @@ -1189,7 +1249,7 @@ void QSGD3D12EnginePrivate::endDrawCalls(bool needsBackbufferTransition) t.lastWaitFenceValue = t.fenceValue; if (t.fenceValue > topFenceValue) topFenceValue = t.fenceValue; - if (t.mipmap) + if (t.mipmap()) pfd.pendingTextureMipMap.insert(id); } if (topFenceValue) { @@ -1208,7 +1268,7 @@ void QSGD3D12EnginePrivate::endDrawCalls(bool needsBackbufferTransition) // Transition the backbuffer for present, if needed. if (needsBackbufferTransition) - transitionResource(backBufferRT(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); + transitionResource(currentBackBufferRT(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); // Go! HRESULT hr = commandList->Close(); @@ -1497,16 +1557,31 @@ void QSGD3D12EnginePrivate::queueScissor(const QRect &rect) commandList->RSSetScissorRects(1, &scissorRect); } -void QSGD3D12EnginePrivate::queueSetRenderTarget() +void QSGD3D12EnginePrivate::queueSetRenderTarget(uint id) { if (!inFrame) { qWarning("%s: Cannot be called outside begin/endFrame", __FUNCTION__); return; } - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = backBufferRTV(); - D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsv; + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle; + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle; + + if (!id) { + rtvHandle = currentBackBufferRTV(); + dsvHandle = backBufferDSV; + } else { + const int idx = id - 1; + Q_ASSERT(idx < renderTargets.count()); + RenderTarget &rt(renderTargets[idx]); + rtvHandle = rt.rtv; + dsvHandle = rt.dsv; + rt.flags |= RenderTarget::NeedsReadBarrier; + } + commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle); + + currentRenderTarget = id; } void QSGD3D12EnginePrivate::queueClearRenderTarget(const QColor &color) @@ -1517,7 +1592,7 @@ void QSGD3D12EnginePrivate::queueClearRenderTarget(const QColor &color) } const float clearColor[] = { float(color.redF()), float(color.blueF()), float(color.greenF()), float(color.alphaF()) }; - commandList->ClearRenderTargetView(backBufferRTV(), clearColor, 0, nullptr); + commandList->ClearRenderTargetView(currentBackBufferRTV(), clearColor, 0, nullptr); } void QSGD3D12EnginePrivate::queueClearDepthStencil(float depthValue, quint8 stencilValue, QSGD3D12Engine::ClearFlags which) @@ -1527,7 +1602,7 @@ void QSGD3D12EnginePrivate::queueClearDepthStencil(float depthValue, quint8 sten return; } - commandList->ClearDepthStencilView(dsv, D3D12_CLEAR_FLAGS(int(which)), depthValue, stencilValue, 0, nullptr); + commandList->ClearDepthStencilView(backBufferDSV, D3D12_CLEAR_FLAGS(int(which)), depthValue, stencilValue, 0, nullptr); } void QSGD3D12EnginePrivate::queueSetBlendFactor(const QVector4D &factor) @@ -1640,9 +1715,12 @@ void QSGD3D12EnginePrivate::queueDraw(QSGGeometry::DrawingMode mode, int count, const uint stride = cpuDescHeapManager.handleSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); D3D12_CPU_DESCRIPTOR_HANDLE dst = pfd.gpuCbvSrvUavHeap->GetCPUDescriptorHandleForHeapStart(); dst.ptr += pfd.cbvSrvUavNextFreeDescriptorIndex * stride; - for (uint id : qAsConst(tframeData.activeTextures)) { - const int idx = id - 1; - device->CopyDescriptorsSimple(1, dst, textures[idx].srv, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + for (const TransientFrameData::ActiveTexture &t : qAsConst(tframeData.activeTextures)) { + Q_ASSERT(t.id); + const int idx = t.id - 1; + const bool isTex = t.type == TransientFrameData::ActiveTexture::TypeTexture; + device->CopyDescriptorsSimple(1, dst, isTex ? textures[idx].srv : renderTargets[idx].srv, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); dst.ptr += stride; } @@ -1669,7 +1747,7 @@ void QSGD3D12EnginePrivate::queueDraw(QSGGeometry::DrawingMode mode, int count, // start a new one beginDrawCalls(); // prepare for the upcoming drawcalls - queueSetRenderTarget(); + queueSetRenderTarget(currentRenderTarget); queueViewport(tframeData.viewport); queueScissor(tframeData.scissor); queueSetBlendFactor(tframeData.blendFactor); @@ -1725,28 +1803,41 @@ void QSGD3D12EnginePrivate::waitGPU() waitForGPU(presentFence); } -uint QSGD3D12EnginePrivate::genTexture() +template<class T> uint newId(T *tbl) { uint id = 0; - for (int i = 0; i < textures.count(); ++i) { - if (!textures[i].entryInUse) { + for (int i = 0; i < tbl->count(); ++i) { + if (!(*tbl)[i].entryInUse()) { id = i + 1; break; } } if (!id) { - textures.resize(textures.size() + 1); - id = textures.count(); + tbl->resize(tbl->size() + 1); + id = tbl->count(); } - Texture &t(textures[id - 1]); - t.entryInUse = true; - t.fenceValue = 0; + (*tbl)[id - 1].flags = 0x01; // reset flags and set EntryInUse return id; } +template<class T> void syncEntryFlags(T *e, int flag, bool b) +{ + if (b) + e->flags |= flag; + else + e->flags &= ~flag; +} + +uint QSGD3D12EnginePrivate::genTexture() +{ + const uint id = newId(&textures); + textures[id - 1].fenceValue = 0; + return id; +} + static inline DXGI_FORMAT textureFormat(QImage::Format format, bool wantsAlpha, bool mipmap, QImage::Format *imageFormat, int *bytesPerPixel) { @@ -1792,17 +1883,17 @@ static inline DXGI_FORMAT textureFormat(QImage::Format format, bool wantsAlpha, } void QSGD3D12EnginePrivate::createTexture(uint id, const QSize &size, QImage::Format format, - QSGD3D12Engine::TextureCreateFlags flags) + QSGD3D12Engine::TextureCreateFlags createFlags) { Q_ASSERT(id); const int idx = id - 1; - Q_ASSERT(idx < textures.count() && textures[idx].entryInUse); + Q_ASSERT(idx < textures.count() && textures[idx].entryInUse()); Texture &t(textures[idx]); - t.alpha = flags & QSGD3D12Engine::CreateWithAlpha; - t.mipmap = flags & QSGD3D12Engine::CreateWithMipMaps; + syncEntryFlags(&t, Texture::Alpha, createFlags & QSGD3D12Engine::CreateWithAlpha); + syncEntryFlags(&t, Texture::MipMap, createFlags & QSGD3D12Engine::CreateWithMipMaps); - const QSize adjustedSize = !t.mipmap ? size : QSGD3D12Engine::mipMapAdjustedSourceSize(size); + const QSize adjustedSize = !t.mipmap() ? size : QSGD3D12Engine::mipMapAdjustedSourceSize(size); D3D12_HEAP_PROPERTIES defaultHeapProp = {}; defaultHeapProp.Type = D3D12_HEAP_TYPE_DEFAULT; @@ -1812,11 +1903,11 @@ void QSGD3D12EnginePrivate::createTexture(uint id, const QSize &size, QImage::Fo textureDesc.Width = adjustedSize.width(); textureDesc.Height = adjustedSize.height(); textureDesc.DepthOrArraySize = 1; - textureDesc.MipLevels = !t.mipmap ? 1 : QSGD3D12Engine::mipMapLevels(adjustedSize); - textureDesc.Format = textureFormat(format, t.alpha, t.mipmap, nullptr, nullptr); + textureDesc.MipLevels = !t.mipmap() ? 1 : QSGD3D12Engine::mipMapLevels(adjustedSize); + textureDesc.Format = textureFormat(format, t.alpha(), t.mipmap(), nullptr, nullptr); textureDesc.SampleDesc.Count = 1; textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - if (t.mipmap) + if (t.mipmap()) textureDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; HRESULT hr = device->CreateCommittedResource(&defaultHeapProp, D3D12_HEAP_FLAG_NONE, &textureDesc, @@ -1836,7 +1927,7 @@ void QSGD3D12EnginePrivate::createTexture(uint id, const QSize &size, QImage::Fo device->CreateShaderResourceView(t.texture.Get(), &srvDesc, t.srv); - if (t.mipmap) { + if (t.mipmap()) { // Mipmap generation will need an UAV for each level that needs to be generated. t.mipUAVs.clear(); for (int level = 1; level < textureDesc.MipLevels; ++level) { @@ -1858,7 +1949,7 @@ void QSGD3D12EnginePrivate::queueTextureResize(uint id, const QSize &size) { Q_ASSERT(id); const int idx = id - 1; - Q_ASSERT(idx < textures.count() && textures[idx].entryInUse); + Q_ASSERT(idx < textures.count() && textures[idx].entryInUse()); Texture &t(textures[idx]); if (!t.texture) { @@ -1866,7 +1957,7 @@ void QSGD3D12EnginePrivate::queueTextureResize(uint id, const QSize &size) return; } - if (t.mipmap) { + if (t.mipmap()) { qWarning("Cannot resize mipmapped texture %u", id); return; } @@ -1935,20 +2026,20 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i return; const int idx = id - 1; - Q_ASSERT(idx < textures.count() && textures[idx].entryInUse); + Q_ASSERT(idx < textures.count() && textures[idx].entryInUse()); Texture &t(textures[idx]); Q_ASSERT(t.texture); // When mipmapping is not in use, image can be smaller than the size passed // to createTexture() and dstPos can specify a non-zero destination position. - if (t.mipmap && (images.count() != 1 || dstPos.count() != 1 || !dstPos[0].isNull())) { + if (t.mipmap() && (images.count() != 1 || dstPos.count() != 1 || !dstPos[0].isNull())) { qWarning("Mipmapped textures (%u) do not support partial uploads", id); return; } // Make life simpler by disallowing queuing a new mipmapped upload before the previous one finishes. - if (t.mipmap && t.fenceValue) { + if (t.mipmap() && t.fenceValue) { qWarning("Attempted to queue mipmapped texture upload (%u) while a previous upload is still in progress", id); return; } @@ -1964,9 +2055,9 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i int totalSize = 0; for (const QImage &image : images) { int bytesPerPixel; - textureFormat(image.format(), t.alpha, t.mipmap, nullptr, &bytesPerPixel); - const int w = !t.mipmap ? image.width() : adjustedTextureSize.width(); - const int h = !t.mipmap ? image.height() : adjustedTextureSize.height(); + textureFormat(image.format(), t.alpha(), t.mipmap(), nullptr, &bytesPerPixel); + const int w = !t.mipmap() ? image.width() : adjustedTextureSize.width(); + const int h = !t.mipmap() ? image.height() : adjustedTextureSize.height(); const int stride = alignedSize(w * bytesPerPixel, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); totalSize += alignedSize(h * stride, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT); } @@ -1996,13 +2087,13 @@ void QSGD3D12EnginePrivate::queueTextureUpload(uint id, const QVector<QImage> &i for (int i = 0; i < images.count(); ++i) { QImage::Format convFormat; int bytesPerPixel; - textureFormat(images[i].format(), t.alpha, t.mipmap, &convFormat, &bytesPerPixel); + textureFormat(images[i].format(), t.alpha(), t.mipmap(), &convFormat, &bytesPerPixel); if (Q_UNLIKELY(debug_render() && i == 0)) qDebug("source image format %d, target format %d, bpp %d", images[i].format(), convFormat, bytesPerPixel); QImage convImage = images[i].format() == convFormat ? images[i] : images[i].convertToFormat(convFormat); - if (t.mipmap && adjustedTextureSize != convImage.size()) + if (t.mipmap() && adjustedTextureSize != convImage.size()) convImage = convImage.scaled(adjustedTextureSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); const int stride = alignedSize(convImage.width() * bytesPerPixel, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); @@ -2076,7 +2167,7 @@ void QSGD3D12EnginePrivate::releaseTexture(uint id) qDebug("releasing texture %d", id); Texture &t(textures[idx]); - if (!t.entryInUse) + if (!t.entryInUse()) return; if (t.texture) { @@ -2097,7 +2188,7 @@ SIZE_T QSGD3D12EnginePrivate::textureSRV(uint id) const { Q_ASSERT(id); const int idx = id - 1; - Q_ASSERT(idx < textures.count() && textures[idx].entryInUse); + Q_ASSERT(idx < textures.count() && textures[idx].entryInUse()); return textures[idx].srv.ptr; } @@ -2110,10 +2201,10 @@ void QSGD3D12EnginePrivate::activateTexture(uint id) Q_ASSERT(id); const int idx = id - 1; - Q_ASSERT(idx < textures.count() && textures[idx].entryInUse); + Q_ASSERT(idx < textures.count() && textures[idx].entryInUse()); // activeTextures is a vector because the order matters - tframeData.activeTextures.append(id); + tframeData.activeTextures.append(TransientFrameData::ActiveTexture(TransientFrameData::ActiveTexture::TypeTexture, id)); if (textures[idx].fenceValue) pframeData[currentPFrameIndex].pendingTextureUploads.insert(id); @@ -2295,4 +2386,121 @@ void QSGD3D12EnginePrivate::deferredDelete(D3D12_CPU_DESCRIPTOR_HANDLE h) (*dq) << e; } +uint QSGD3D12EnginePrivate::genRenderTarget() +{ + return newId(&renderTargets); +} + +void QSGD3D12EnginePrivate::createRenderTarget(uint id, const QSize &size, const QVector4D &clearColor, int samples) +{ + Q_ASSERT(id); + const int idx = id - 1; + Q_ASSERT(idx < renderTargets.count() && renderTargets[idx].entryInUse()); + RenderTarget &rt(renderTargets[idx]); + + ID3D12Resource *res = createColorBuffer(rt.rtv, size, clearColor, samples); + if (res) + rt.color.Attach(res); + + ID3D12Resource *dsres = createDepthStencil(rt.dsv, size, samples); + if (dsres) + rt.ds.Attach(dsres); + + rt.rtv = cpuDescHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + rt.dsv = cpuDescHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + rt.srv = cpuDescHeapManager.allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + device->CreateRenderTargetView(rt.color.Get(), nullptr, rt.rtv); + device->CreateDepthStencilView(rt.ds.Get(), nullptr, rt.dsv); + + const bool multisample = rt.color->GetDesc().SampleDesc.Count > 1; + syncEntryFlags(&rt, RenderTarget::Multisample, multisample); + + if (!multisample) { + device->CreateShaderResourceView(rt.color.Get(), nullptr, rt.srv); + } else { + D3D12_HEAP_PROPERTIES defaultHeapProp = {}; + defaultHeapProp.Type = D3D12_HEAP_TYPE_DEFAULT; + + D3D12_RESOURCE_DESC textureDesc = {}; + textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + textureDesc.Width = size.width(); + textureDesc.Height = size.height(); + textureDesc.DepthOrArraySize = 1; + textureDesc.MipLevels = 1; + textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + textureDesc.SampleDesc.Count = 1; + textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + + HRESULT hr = device->CreateCommittedResource(&defaultHeapProp, D3D12_HEAP_FLAG_NONE, &textureDesc, + D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&rt.colorResolve)); + if (FAILED(hr)) { + qWarning("Failed to create resolve buffer: 0x%x", hr); + return; + } + + device->CreateShaderResourceView(rt.colorResolve.Get(), nullptr, rt.srv); + } + +} + +void QSGD3D12EnginePrivate::releaseRenderTarget(uint id) +{ + if (!id) + return; + + const int idx = id - 1; + Q_ASSERT(idx < renderTargets.count()); + RenderTarget &rt(renderTargets[idx]); + if (!rt.entryInUse()) + return; + + if (rt.colorResolve) { + deferredDelete(rt.colorResolve); + rt.colorResolve = nullptr; + } + if (rt.color) { + deferredDelete(rt.color); + rt.color = nullptr; + deferredDelete(rt.rtv); + deferredDelete(rt.srv); + } + if (rt.ds) { + deferredDelete(rt.ds); + rt.ds = nullptr; + deferredDelete(rt.dsv); + } + + rt.flags &= ~RenderTarget::EntryInUse; +} + +void QSGD3D12EnginePrivate::activateRenderTargetAsTexture(uint id) +{ + if (!inFrame) { + qWarning("%s: Cannot be called outside begin/endFrame", __FUNCTION__); + return; + } + + Q_ASSERT(id); + const int idx = id - 1; + Q_ASSERT(idx < renderTargets.count()); + RenderTarget &rt(renderTargets[idx]); + Q_ASSERT(rt.entryInUse() && rt.color); + + if (rt.flags & RenderTarget::NeedsReadBarrier) { + if (rt.flags & RenderTarget::Multisample) { + transitionResource(rt.color.Get(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE); + transitionResource(rt.colorResolve.Get(), commandList.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RESOLVE_DEST); + commandList->ResolveSubresource(rt.colorResolve.Get(), 0, rt.color.Get(), 0, DXGI_FORMAT_R8G8B8A8_UNORM); + transitionResource(rt.colorResolve.Get(), commandList.Get(), D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + transitionResource(rt.color.Get(), commandList.Get(), D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET); + } else { + transitionResource(rt.color.Get(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + } + rt.flags &= ~RenderTarget::NeedsReadBarrier; + } + + tframeData.activeTextures.append(TransientFrameData::ActiveTexture::ActiveTexture(TransientFrameData::ActiveTexture::TypeRenderTarget, id)); +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h index 7236053cf4..8ef1281554 100644 --- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h +++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p.h @@ -288,7 +288,7 @@ public: void queueViewport(const QRect &rect); void queueScissor(const QRect &rect); - void queueSetRenderTarget(); + void queueSetRenderTarget(uint id = 0); void queueClearRenderTarget(const QColor &color); void queueClearDepthStencil(float depthValue, quint8 stencilValue, ClearFlags which); void queueSetBlendFactor(const QVector4D &factor); @@ -324,6 +324,11 @@ public: SIZE_T textureSRV(uint id) const; void activateTexture(uint id); + uint genRenderTarget(); + void createRenderTarget(uint id, const QSize &size, const QVector4D &clearColor, int samples); + void releaseRenderTarget(uint id); + void activateRenderTargetAsTexture(uint id); + private: QSGD3D12EnginePrivate *d; Q_DISABLE_COPY(QSGD3D12Engine) diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h index 573dbded8e..1003f2dc30 100644 --- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h +++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12engine_p_p.h @@ -148,7 +148,7 @@ public: void queueViewport(const QRect &rect); void queueScissor(const QRect &rect); - void queueSetRenderTarget(); + void queueSetRenderTarget(uint id); void queueClearRenderTarget(const QColor &color); void queueClearDepthStencil(float depthValue, quint8 stencilValue, QSGD3D12Engine::ClearFlags which); void queueSetBlendFactor(const QVector4D &factor); @@ -172,6 +172,11 @@ public: SIZE_T textureSRV(uint id) const; void activateTexture(uint id); + uint genRenderTarget(); + void createRenderTarget(uint id, const QSize &size, const QVector4D &clearColor, int samples); + void releaseRenderTarget(uint id); + void activateRenderTargetAsTexture(uint id); + // the device is intentionally hidden here. all resources have to go // through the engine and, unlike with GL, cannot just be created in random // places due to the need for proper tracking, managing and releasing. @@ -184,6 +189,8 @@ private: void ensureGPUDescriptorHeap(int cbvSrvUavDescriptorCount); DXGI_SAMPLE_DESC makeSampleDesc(DXGI_FORMAT format, int samples); + ID3D12Resource *createColorBuffer(D3D12_CPU_DESCRIPTOR_HANDLE viewHandle, const QSize &size, + const QVector4D &clearColor, int samples); ID3D12Resource *createDepthStencil(D3D12_CPU_DESCRIPTOR_HANDLE viewHandle, const QSize &size, int samples); QSGD3D12CPUWaitableFence *createCPUWaitableFence() const; @@ -196,8 +203,8 @@ private: ID3D12Resource *createBuffer(int size); - ID3D12Resource *backBufferRT() const; - D3D12_CPU_DESCRIPTOR_HANDLE backBufferRTV() const; + ID3D12Resource *currentBackBufferRT() const; + D3D12_CPU_DESCRIPTOR_HANDLE currentBackBufferRTV() const; struct CPUBufferRef { const quint8 *p = nullptr; @@ -253,9 +260,9 @@ private: ComPtr<ID3D12CommandQueue> commandQueue; ComPtr<ID3D12CommandQueue> copyCommandQueue; ComPtr<IDXGISwapChain3> swapChain; - ComPtr<ID3D12Resource> renderTargets[SWAP_CHAIN_BUFFER_COUNT]; - D3D12_CPU_DESCRIPTOR_HANDLE rtv[SWAP_CHAIN_BUFFER_COUNT]; - D3D12_CPU_DESCRIPTOR_HANDLE dsv; + ComPtr<ID3D12Resource> backBufferRT[SWAP_CHAIN_BUFFER_COUNT]; + D3D12_CPU_DESCRIPTOR_HANDLE backBufferRTV[SWAP_CHAIN_BUFFER_COUNT]; + D3D12_CPU_DESCRIPTOR_HANDLE backBufferDSV; ComPtr<ID3D12Resource> depthStencil; ComPtr<ID3D12CommandAllocator> commandAllocator[MAX_FRAMES_IN_FLIGHT]; ComPtr<ID3D12CommandAllocator> copyCommandAllocator; @@ -284,7 +291,15 @@ private: QCache<QSGD3D12RootSignature, RootSigCacheEntry> rootSigCache; struct Texture { - bool entryInUse = false; + enum Flag { + EntryInUse = 0x01, + Alpha = 0x02, + MipMap = 0x04 + }; + int flags = 0; + bool entryInUse() const { return flags & EntryInUse; } + bool alpha() const { return flags & Alpha; } + bool mipmap() const { return flags & MipMap; } ComPtr<ID3D12Resource> texture; D3D12_CPU_DESCRIPTOR_HANDLE srv; quint64 fenceValue = 0; @@ -298,8 +313,6 @@ private: }; QVector<StagingBuffer> stagingBuffers; QVector<D3D12_CPU_DESCRIPTOR_HANDLE> mipUAVs; - bool alpha = true; - bool mipmap = false; }; QVector<Texture> textures; @@ -309,7 +322,17 @@ private: struct TransientFrameData { QSGGeometry::DrawingMode drawingMode; bool indexBufferSet; - QVector<uint> activeTextures; + struct ActiveTexture { + enum Type { + TypeTexture, + TypeRenderTarget + }; + Type type = TypeTexture; + uint id = 0; + ActiveTexture(Type type, uint id) : type(type), id(id) { } + ActiveTexture() { } + }; + QVector<ActiveTexture> activeTextures; int drawCount; ID3D12PipelineState *lastPso; ID3D12RootSignature *lastRootSig; @@ -334,6 +357,25 @@ private: }; MipMapGen mipmapper; + + struct RenderTarget { + enum Flag { + EntryInUse = 0x01, + NeedsReadBarrier = 0x02, + Multisample = 0x04 + }; + int flags = 0; + bool entryInUse() const { return flags & EntryInUse; } + ComPtr<ID3D12Resource> color; + ComPtr<ID3D12Resource> colorResolve; + D3D12_CPU_DESCRIPTOR_HANDLE rtv; + ComPtr<ID3D12Resource> ds; + D3D12_CPU_DESCRIPTOR_HANDLE dsv; + D3D12_CPU_DESCRIPTOR_HANDLE srv; + }; + + QVector<RenderTarget> renderTargets; + uint currentRenderTarget; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12layer.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12layer.cpp new file mode 100644 index 0000000000..6c137a718e --- /dev/null +++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12layer.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgd3d12layer_p.h" + +QT_BEGIN_NAMESPACE + +QSGD3D12Layer::QSGD3D12Layer(QSGD3D12RenderContext *rc) + : m_rc(rc) +{ +} + +QSGD3D12Layer::~QSGD3D12Layer() +{ + cleanup(); +} + +int QSGD3D12Layer::textureId() const +{ + return 0; +} + +QSize QSGD3D12Layer::textureSize() const +{ + return QSize(); +} + +bool QSGD3D12Layer::hasAlphaChannel() const +{ + return true; +} + +bool QSGD3D12Layer::hasMipmaps() const +{ + // ### + return false; +} + +QRectF QSGD3D12Layer::normalizedTextureSubRect() const +{ + return QRectF(0, 0, 1, 1); // ### mirror h/v +} + +void QSGD3D12Layer::bind() +{ + +} + +bool QSGD3D12Layer::updateTexture() +{ + return false; +} + +void QSGD3D12Layer::setItem(QSGNode *item) +{ + +} + +void QSGD3D12Layer::setRect(const QRectF &rect) +{ + +} + +void QSGD3D12Layer::setSize(const QSize &size) +{ + +} + +void QSGD3D12Layer::scheduleUpdate() +{ + +} + +QImage QSGD3D12Layer::toImage() const +{ + // ### figure out something for item grab support + return QImage(); +} + +void QSGD3D12Layer::setLive(bool live) +{ + +} + +void QSGD3D12Layer::setRecursive(bool recursive) +{ + +} + +void QSGD3D12Layer::setFormat(GLenum format) +{ + +} + +void QSGD3D12Layer::setHasMipmaps(bool mipmap) +{ + +} + +void QSGD3D12Layer::setDevicePixelRatio(qreal ratio) +{ + +} + +void QSGD3D12Layer::setMirrorHorizontal(bool mirror) +{ + +} + +void QSGD3D12Layer::setMirrorVertical(bool mirror) +{ + +} + +void QSGD3D12Layer::markDirtyTexture() +{ + +} + +void QSGD3D12Layer::invalidated() +{ + cleanup(); +} + +void QSGD3D12Layer::cleanup() +{ +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12layer_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12layer_p.h new file mode 100644 index 0000000000..cfd15ae761 --- /dev/null +++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12layer_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGD3D12LAYER_P_H +#define QSGD3D12LAYER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qsgadaptationlayer_p.h> + +QT_BEGIN_NAMESPACE + +class QSGD3D12RenderContext; + +class QSGD3D12Layer : public QSGLayer +{ +public: + QSGD3D12Layer(QSGD3D12RenderContext *rc); + ~QSGD3D12Layer(); + + int textureId() const override; + QSize textureSize() const override; + bool hasAlphaChannel() const override; + bool hasMipmaps() const override; + QRectF normalizedTextureSubRect() const override; + void bind() override; + + bool updateTexture() override; + + void setItem(QSGNode *item) override; + void setRect(const QRectF &rect) override; + void setSize(const QSize &size) override; + void scheduleUpdate() override; + QImage toImage() const override; + void setLive(bool live) override; + void setRecursive(bool recursive) override; + void setFormat(GLenum format) override; + void setHasMipmaps(bool mipmap) override; + void setDevicePixelRatio(qreal ratio) override; + void setMirrorHorizontal(bool mirror) override; + void setMirrorVertical(bool mirror) override; + void markDirtyTexture() override; + void invalidated() override; + +private: + void cleanup(); + + QSGD3D12RenderContext *m_rc; +}; + +QT_END_NAMESPACE + +#endif // QSGD3D12LAYER_P_H diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12texture.cpp b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12texture.cpp index c1164b5add..0250023fdf 100644 --- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12texture.cpp +++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12texture.cpp @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE void QSGD3D12Texture::setImage(const QImage &image, uint flags) { - // ### atlas + // ### atlas? const bool alphaRequest = flags & QSGRenderContext::CreateTexture_Alpha; m_alphaWanted = alphaRequest && image.hasAlphaChannel(); @@ -93,16 +93,6 @@ QRectF QSGD3D12Texture::normalizedTextureSubRect() const return QRectF(0, 0, 1, 1); } -bool QSGD3D12Texture::isAtlasTexture() const -{ - return false; // ### -} - -QSGTexture *QSGD3D12Texture::removedFromAtlas() const -{ - return nullptr; // ### -} - void QSGD3D12Texture::bind() { // Called when the texture material updates the pipeline state. diff --git a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12texture_p.h b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12texture_p.h index 35f65420fa..510bb65139 100644 --- a/src/quick/scenegraph/adaptations/d3d12/qsgd3d12texture_p.h +++ b/src/quick/scenegraph/adaptations/d3d12/qsgd3d12texture_p.h @@ -70,8 +70,6 @@ public: bool hasAlphaChannel() const override; bool hasMipmaps() const override; QRectF normalizedTextureSubRect() const override; - bool isAtlasTexture() const override; - QSGTexture *removedFromAtlas() const override; void bind() override; SIZE_T srv() const; |