blob: 01b1eb2fd8b1da82aee5fd9b3bc309c489c77e08 [file] [log] [blame]
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001/*
Jim Van Verth03b8ab22020-02-24 11:36:15 -05002 * Copyright 2020 Google LLC
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05008#include "src/gpu/d3d/GrD3DGpu.h"
9
Jim Van Verth9aa9a682020-04-01 10:13:48 -040010#include "include/gpu/d3d/GrD3DBackendContext.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050011#include "src/gpu/d3d/GrD3DCaps.h"
12#include "src/gpu/d3d/GrD3DOpsRenderPass.h"
Jim Van Verthaa90dad2020-03-30 15:00:39 -040013#include "src/gpu/d3d/GrD3DTexture.h"
14#include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
15#include "src/gpu/d3d/GrD3DUtil.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050016
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050017sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
18 const GrContextOptions& contextOptions, GrContext* context) {
19 return sk_sp<GrGpu>(new GrD3DGpu(context, contextOptions, backendContext));
20}
21
Greg Daniel83ed2132020-03-24 13:15:33 -040022// This constant determines how many OutstandingCommandLists are allocated together as a block in
23// the deque. As such it needs to balance allocating too much memory vs. incurring
24// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
25// command lists we expect to see.
26static const int kDefaultOutstandingAllocCnt = 8;
27
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050028GrD3DGpu::GrD3DGpu(GrContext* context, const GrContextOptions& contextOptions,
29 const GrD3DBackendContext& backendContext)
Jim Van Verth03b8ab22020-02-24 11:36:15 -050030 : INHERITED(context)
31 , fDevice(backendContext.fDevice)
Greg Daniel02c45902020-03-09 10:58:09 -040032
33 , fQueue(backendContext.fQueue)
Greg Daniel83ed2132020-03-24 13:15:33 -040034 , fResourceProvider(this)
35 , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt) {
Jim Van Verth8ec13302020-02-26 12:59:56 -050036 fCaps.reset(new GrD3DCaps(contextOptions,
Jim Van Verth9aa9a682020-04-01 10:13:48 -040037 backendContext.fAdapter.get(),
38 backendContext.fDevice.get()));
Greg Daniel85da3362020-03-09 15:18:35 -040039
40 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
Greg Daniele52c9782020-03-23 14:18:37 -040041 SkASSERT(fCurrentDirectCommandList);
Greg Daniel83ed2132020-03-24 13:15:33 -040042
43 SkASSERT(fCurrentFenceValue == 0);
44 SkDEBUGCODE(HRESULT hr = ) fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
45 IID_PPV_ARGS(&fFence));
46 SkASSERT(SUCCEEDED(hr));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050047}
48
Greg Daniel83ed2132020-03-24 13:15:33 -040049GrD3DGpu::~GrD3DGpu() {
50 this->destroyResources();
51}
52
53void GrD3DGpu::destroyResources() {
54 if (fCurrentDirectCommandList) {
55 fCurrentDirectCommandList->close();
56 fCurrentDirectCommandList.reset();
57 }
58
59 // We need to make sure everything has finished on the queue.
60 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
61 HANDLE fenceEvent;
62 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
63 SkASSERT(fenceEvent);
64 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
65 SkASSERT(SUCCEEDED(hr));
66 WaitForSingleObject(fenceEvent, INFINITE);
67 CloseHandle(fenceEvent);
68 }
69
70 SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
71
72 // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
73 // for calling the destructor on each of them as well.
74 while (!fOutstandingCommandLists.empty()) {
75 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.back();
76 SkASSERT(list->fFenceValue <= fenceValue);
77 // No reason to recycle the command lists since we are destroying all resources anyways.
78 list->~OutstandingCommandList();
79 fOutstandingCommandLists.pop_back();
80 }
81}
Greg Daniel31a7b072020-02-26 15:31:49 -050082
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050083GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
84 GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds,
85 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -050086 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050087 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -050088 if (!fCachedOpsRenderPass) {
89 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
90 }
91
92 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
93 return nullptr;
94 }
95 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050096}
97
Greg Daniel83ed2132020-03-24 13:15:33 -040098void GrD3DGpu::submitDirectCommandList() {
99 SkASSERT(fCurrentDirectCommandList);
100
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400101 fCurrentDirectCommandList->submit(fQueue.get());
Greg Daniel83ed2132020-03-24 13:15:33 -0400102
103 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
104 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
105
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400106 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400107 SkASSERT(SUCCEEDED(hr));
108
109 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
110
111 // This should be done after we have a new command list in case the freeing of any resources
112 // held by a finished command list causes us send a new command to the gpu (like changing the
113 // resource state.
114 this->checkForFinishedCommandLists();
115
116 SkASSERT(fCurrentDirectCommandList);
117}
118
119void GrD3DGpu::checkForFinishedCommandLists() {
120 uint64_t currentFenceValue = fFence->GetCompletedValue();
121
122 // Iterate over all the outstanding command lists to see if any have finished. The commands
123 // lists are in order from oldest to newest, so we start at the front to check if their fence
124 // value is less than the last signaled value. If so we pop it off and move onto the next.
125 // Repeat till we find a command list that has not finished yet (and all others afterwards are
126 // also guaranteed to not have finished).
127 SkDeque::F2BIter iter(fOutstandingCommandLists);
128 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
129 while (curList && curList->fFenceValue <= currentFenceValue) {
130 curList = (const OutstandingCommandList*)iter.next();
131 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400132 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400133 // Since we used placement new we are responsible for calling the destructor manually.
134 front->~OutstandingCommandList();
135 fOutstandingCommandLists.pop_front();
136 }
137}
138
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500139void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400140 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
141
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500142 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400143 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500144}
145
146void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
147 // TODO
148}
149
150sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
151 const GrBackendFormat& format,
152 GrRenderable renderable,
153 int renderTargetSampleCnt,
154 SkBudgeted budgeted,
155 GrProtected isProtected,
156 int mipLevelCount,
157 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400158 DXGI_FORMAT dxgiFormat;
159 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
160 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
161
162 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
163
164 if (renderable == GrRenderable::kYes) {
165 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
166 }
167
168 // This desc refers to the texture that will be read by the client. Thus even if msaa is
169 // requested, this describes the resolved texture. Therefore we always have samples set
170 // to 1.
171 SkASSERT(mipLevelCount > 0);
172 D3D12_RESOURCE_DESC resourceDesc;
173 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
174 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
175 // might want to manually set alignment to 4KB for smaller textures
176 resourceDesc.Alignment = 0;
177 resourceDesc.Width = dimensions.fWidth;
178 resourceDesc.Height = dimensions.fHeight;
179 resourceDesc.DepthOrArraySize = 1;
180 resourceDesc.MipLevels = mipLevelCount;
181 resourceDesc.Format = dxgiFormat;
182 resourceDesc.SampleDesc.Count = 1;
183 resourceDesc.SampleDesc.Quality = 0; // quality levels are only supported for tiled resources
184 // so ignore for now
185 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle for now
186 resourceDesc.Flags = usageFlags;
187
188 GrMipMapsStatus mipMapsStatus =
189 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
190
191 sk_sp<GrD3DTexture> tex;
192 if (renderable == GrRenderable::kYes) {
193 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
194 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
195 mipMapsStatus);
196 } else {
197 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
198 mipMapsStatus);
199 }
200
201 if (!tex) {
202 return nullptr;
203 }
204
205 if (levelClearMask) {
206 // TODO
207 }
208 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500209}
210
211sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
212 const GrBackendFormat& format,
213 SkBudgeted budgeted,
214 GrMipMapped mipMapped,
215 GrProtected isProtected,
216 const void* data, size_t dataSize) {
217 // TODO
218 return nullptr;
219}
220
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400221static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400222 if (!info.fResource.get()) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400223 return false;
224 }
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400225 return true;
226}
227
228static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
229 if (!caps.isFormatTexturable(info.fFormat)) {
230 return false;
231 }
232 return true;
233}
234
235static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
236 int sampleCnt) {
237 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
238 return false;
239 }
240 return true;
241}
242
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400243sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
244 GrWrapOwnership,
245 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400246 GrIOType ioType) {
247 GrD3DTextureResourceInfo textureInfo;
248 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
249 return nullptr;
250 }
251
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400252 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400253 return nullptr;
254 }
255
256 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
257 return nullptr;
258 }
259
260 // TODO: support protected context
261 if (tex.isProtected()) {
262 return nullptr;
263 }
264
265 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
266 SkASSERT(state);
267 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
268 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500269}
270
271sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400272 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500273 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400274 GrD3DTextureResourceInfo textureInfo;
275 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
276 return nullptr;
277 }
278
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400279 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400280 return nullptr;
281 }
282
283 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
284 return nullptr;
285 }
286
287 // TODO: support protected context
288 if (tex.isProtected()) {
289 return nullptr;
290 }
291
292 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
293 SkASSERT(state);
294 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
295 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500296}
297
298sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
299 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500300 GrWrapOwnership ownership,
301 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400302 GrD3DTextureResourceInfo textureInfo;
303 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
304 return nullptr;
305 }
306
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400307 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400308 return nullptr;
309 }
310
311 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
312 return nullptr;
313 }
314 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
315 return nullptr;
316 }
317
318 // TODO: support protected context
319 if (tex.isProtected()) {
320 return nullptr;
321 }
322
323 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
324
325 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
326 SkASSERT(state);
327
328 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
329 sampleCnt, cacheable,
330 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500331}
332
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400333sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400334 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
335 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
336 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
337 // creating and owning the MSAA images.
338 if (rt.sampleCnt() > 1) {
339 return nullptr;
340 }
341
342 GrD3DTextureResourceInfo info;
343 if (!rt.getD3DTextureResourceInfo(&info)) {
344 return nullptr;
345 }
346
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400347 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400348 return nullptr;
349 }
350
351 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
352 return nullptr;
353 }
354
355 // TODO: support protected context
356 if (rt.isProtected()) {
357 return nullptr;
358 }
359
360 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
361
362 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
363 this, rt.dimensions(), 1, info, std::move(state));
364
365 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
366 SkASSERT(!rt.stencilBits());
367 if (tgt) {
368 SkASSERT(tgt->canAttemptStencilAttachment());
369 }
370
371 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500372}
373
374sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400375 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400376
377 GrD3DTextureResourceInfo textureInfo;
378 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
379 return nullptr;
380 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400381 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400382 return nullptr;
383 }
384
385 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
386 return nullptr;
387 }
388
389 // TODO: support protected context
390 if (tex.isProtected()) {
391 return nullptr;
392 }
393
394 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
395 if (!sampleCnt) {
396 return nullptr;
397 }
398
399 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
400 SkASSERT(state);
401
402 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
403 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500404}
405
406sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
407 GrAccessPattern accessPattern, const void*) {
408 // TODO
409 return nullptr;
410}
411
412GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
413 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
414 // TODO
415 return nullptr;
416}
417
418GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400419 const GrBackendFormat& format,
420 GrRenderable,
421 GrMipMapped mipMapped,
422 GrProtected,
423 const BackendTextureData*) {
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500424 // TODO
425 return GrBackendTexture();
426}
427
428GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400429 const GrBackendFormat& format,
430 GrMipMapped mipMapped,
431 GrProtected,
432 const BackendTextureData*) {
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500433 // TODO
434 return GrBackendTexture();
435}
436
437void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
438 // TODO
439}
440
Robert Phillips979b2232020-02-20 10:47:29 -0500441bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
442 return false;
443}
444
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500445#if GR_TEST_UTILS
446bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
447 // TODO
448 return false;
449}
450
451GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400452 GrColorType colorType) {
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500453 // TODO
454 return GrBackendRenderTarget();
455}
456
457void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) {}
458#endif