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