1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/dawn/GrDawnBuffer.h"
9
10 #include "src/gpu/dawn/GrDawnGpu.h"
11
12 namespace {
GrGpuBufferTypeToDawnUsageBit(GrGpuBufferType type)13 wgpu::BufferUsage GrGpuBufferTypeToDawnUsageBit(GrGpuBufferType type) {
14 switch (type) {
15 case GrGpuBufferType::kVertex:
16 return wgpu::BufferUsage::Vertex | wgpu::BufferUsage::CopyDst;
17 case GrGpuBufferType::kIndex:
18 return wgpu::BufferUsage::Index | wgpu::BufferUsage::CopyDst;
19 case GrGpuBufferType::kXferCpuToGpu:
20 return wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
21 case GrGpuBufferType::kXferGpuToCpu:
22 return wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
23 default:
24 SkASSERT(!"buffer type not supported by Dawn");
25 return wgpu::BufferUsage::Vertex;
26 }
27 }
28 }
29
GrDawnBuffer(GrDawnGpu * gpu,size_t sizeInBytes,GrGpuBufferType type,GrAccessPattern pattern)30 GrDawnBuffer::GrDawnBuffer(GrDawnGpu* gpu, size_t sizeInBytes, GrGpuBufferType type,
31 GrAccessPattern pattern)
32 : INHERITED(gpu, sizeInBytes, type, pattern) {
33 wgpu::BufferDescriptor bufferDesc;
34 bufferDesc.size = sizeInBytes;
35 bufferDesc.usage = GrGpuBufferTypeToDawnUsageBit(type);
36
37 if (bufferDesc.usage & wgpu::BufferUsage::MapRead) {
38 SkASSERT(!SkToBool(bufferDesc.usage & wgpu::BufferUsage::MapWrite));
39 fMappable = Mappable::kReadOnly;
40 } else if (bufferDesc.usage & wgpu::BufferUsage::MapWrite) {
41 fMappable = Mappable::kWriteOnly;
42 }
43
44 if (fMappable == Mappable::kNot || fMappable == Mappable::kReadOnly) {
45 fBuffer = this->getDawnGpu()->device().CreateBuffer(&bufferDesc);
46 } else {
47 bufferDesc.mappedAtCreation = true;
48 fBuffer = this->getDawnGpu()->device().CreateBuffer(&bufferDesc);
49 fMapPtr = fBuffer.GetMappedRange();
50 }
51
52 this->registerWithCache(SkBudgeted::kYes);
53 }
54
~GrDawnBuffer()55 GrDawnBuffer::~GrDawnBuffer() {
56 }
57
onMap()58 void GrDawnBuffer::onMap() {
59 if (this->wasDestroyed()) {
60 return;
61 }
62
63 if (fMappable == Mappable::kNot) {
64 GrStagingBufferManager::Slice slice =
65 this->getDawnGpu()->stagingBufferManager()->allocateStagingBufferSlice(
66 this->size());
67 fStagingBuffer = static_cast<GrDawnBuffer*>(slice.fBuffer)->get();
68 fStagingOffset = slice.fOffset;
69 fMapPtr = slice.fOffsetMapPtr;
70 } else {
71 // We always create this buffers mapped or if they've been used on the gpu before we use the
72 // async map callback to know when it is safe to reuse them. Thus by the time we get here
73 // the buffer should always be mapped.
74 SkASSERT(this->isMapped());
75 }
76 }
77
onUnmap()78 void GrDawnBuffer::onUnmap() {
79 if (this->wasDestroyed()) {
80 return;
81 }
82
83 if (fMappable == Mappable::kNot) {
84 this->getDawnGpu()->getCopyEncoder().CopyBufferToBuffer(fStagingBuffer, fStagingOffset,
85 fBuffer, 0, this->size());
86 } else {
87 fBuffer.Unmap();
88 }
89 }
90
onUpdateData(const void * src,size_t srcSizeInBytes)91 bool GrDawnBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) {
92 if (this->wasDestroyed()) {
93 return false;
94 }
95 this->map();
96 memcpy(fMapPtr, src, srcSizeInBytes);
97 this->unmap();
98 return true;
99 }
100
getDawnGpu() const101 GrDawnGpu* GrDawnBuffer::getDawnGpu() const {
102 SkASSERT(!this->wasDestroyed());
103 return static_cast<GrDawnGpu*>(this->getGpu());
104 }
105
callback_read(WGPUBufferMapAsyncStatus status,void * userData)106 static void callback_read(WGPUBufferMapAsyncStatus status, void* userData) {
107 auto buffer = static_cast<GrDawnBuffer*>(userData);
108 buffer->setMapPtr(const_cast<void*>(buffer->get().GetConstMappedRange()));
109 }
110
callback_write(WGPUBufferMapAsyncStatus status,void * userData)111 static void callback_write(WGPUBufferMapAsyncStatus status, void* userData) {
112 auto buffer = static_cast<GrDawnBuffer*>(userData);
113 buffer->setMapPtr(buffer->get().GetMappedRange());
114 }
115
mapWriteAsync()116 void GrDawnBuffer::mapWriteAsync() {
117 SkASSERT(!this->isMapped());
118 fBuffer.MapAsync(wgpu::MapMode::Write, 0, 0, callback_write, this);
119 }
mapReadAsync()120 void GrDawnBuffer::mapReadAsync() {
121 SkASSERT(!this->isMapped());
122 fBuffer.MapAsync(wgpu::MapMode::Read, 0, 0, callback_read, this);
123 }
124