• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/opengl/BufferGL.h"
16 
17 #include "dawn_native/CommandBuffer.h"
18 #include "dawn_native/opengl/DeviceGL.h"
19 
20 namespace dawn_native { namespace opengl {
21 
22     // Buffer
23 
24     // static
CreateInternalBuffer(Device * device,const BufferDescriptor * descriptor,bool shouldLazyClear)25     ResultOrError<Ref<Buffer>> Buffer::CreateInternalBuffer(Device* device,
26                                                             const BufferDescriptor* descriptor,
27                                                             bool shouldLazyClear) {
28         Ref<Buffer> buffer = AcquireRef(new Buffer(device, descriptor, shouldLazyClear));
29         if (descriptor->mappedAtCreation) {
30             DAWN_TRY(buffer->MapAtCreationInternal());
31         }
32 
33         return std::move(buffer);
34     }
35 
Buffer(Device * device,const BufferDescriptor * descriptor)36     Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
37         : BufferBase(device, descriptor) {
38         // Allocate at least 4 bytes so clamped accesses are always in bounds.
39         mAllocatedSize = std::max(GetSize(), uint64_t(4u));
40 
41         device->gl.GenBuffers(1, &mBuffer);
42         device->gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
43 
44         // The buffers with mappedAtCreation == true will be initialized in
45         // BufferBase::MapAtCreation().
46         if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting) &&
47             !descriptor->mappedAtCreation) {
48             std::vector<uint8_t> clearValues(mAllocatedSize, 1u);
49             device->gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, clearValues.data(),
50                                   GL_STATIC_DRAW);
51         } else {
52             // Buffers start zeroed if you pass nullptr to glBufferData.
53             device->gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, nullptr, GL_STATIC_DRAW);
54         }
55     }
56 
Buffer(Device * device,const BufferDescriptor * descriptor,bool shouldLazyClear)57     Buffer::Buffer(Device* device, const BufferDescriptor* descriptor, bool shouldLazyClear)
58         : Buffer(device, descriptor) {
59         if (!shouldLazyClear) {
60             SetIsDataInitialized();
61         }
62     }
63 
64     Buffer::~Buffer() = default;
65 
GetHandle() const66     GLuint Buffer::GetHandle() const {
67         return mBuffer;
68     }
69 
EnsureDataInitialized()70     bool Buffer::EnsureDataInitialized() {
71         if (!NeedsInitialization()) {
72             return false;
73         }
74 
75         InitializeToZero();
76         return true;
77     }
78 
EnsureDataInitializedAsDestination(uint64_t offset,uint64_t size)79     bool Buffer::EnsureDataInitializedAsDestination(uint64_t offset, uint64_t size) {
80         if (!NeedsInitialization()) {
81             return false;
82         }
83 
84         if (IsFullBufferRange(offset, size)) {
85             SetIsDataInitialized();
86             return false;
87         }
88 
89         InitializeToZero();
90         return true;
91     }
92 
EnsureDataInitializedAsDestination(const CopyTextureToBufferCmd * copy)93     bool Buffer::EnsureDataInitializedAsDestination(const CopyTextureToBufferCmd* copy) {
94         if (!NeedsInitialization()) {
95             return false;
96         }
97 
98         if (IsFullBufferOverwrittenInTextureToBufferCopy(copy)) {
99             SetIsDataInitialized();
100             return false;
101         }
102 
103         InitializeToZero();
104         return true;
105     }
106 
InitializeToZero()107     void Buffer::InitializeToZero() {
108         ASSERT(NeedsInitialization());
109 
110         const uint64_t size = GetAllocatedSize();
111         Device* device = ToBackend(GetDevice());
112 
113         const std::vector<uint8_t> clearValues(size, 0u);
114         device->gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
115         device->gl.BufferSubData(GL_ARRAY_BUFFER, 0, size, clearValues.data());
116         device->IncrementLazyClearCountForTesting();
117 
118         SetIsDataInitialized();
119     }
120 
IsCPUWritableAtCreation() const121     bool Buffer::IsCPUWritableAtCreation() const {
122         // TODO(enga): All buffers in GL can be mapped. Investigate if mapping them will cause the
123         // driver to migrate it to shared memory.
124         return true;
125     }
126 
MapAtCreationImpl()127     MaybeError Buffer::MapAtCreationImpl() {
128         const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
129         gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
130         mMappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, 0, GetSize(), GL_MAP_WRITE_BIT);
131         return {};
132     }
133 
MapAsyncImpl(wgpu::MapMode mode,size_t offset,size_t size)134     MaybeError Buffer::MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) {
135         const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
136 
137         // It is an error to map an empty range in OpenGL. We always have at least a 4-byte buffer
138         // so we extend the range to be 4 bytes.
139         if (size == 0) {
140             if (offset != 0) {
141                 offset -= 4;
142             }
143             size = 4;
144         }
145 
146         EnsureDataInitialized();
147 
148         // This does GPU->CPU synchronization, we could require a high
149         // version of OpenGL that would let us map the buffer unsynchronized.
150         gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
151         void* mappedData = nullptr;
152         if (mode & wgpu::MapMode::Read) {
153             mappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, offset, size, GL_MAP_READ_BIT);
154         } else {
155             ASSERT(mode & wgpu::MapMode::Write);
156             mappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, offset, size, GL_MAP_WRITE_BIT);
157         }
158 
159         // The frontend asks that the pointer returned by GetMappedPointerImpl is from the start of
160         // the resource but OpenGL gives us the pointer at offset. Remove the offset.
161         mMappedData = static_cast<uint8_t*>(mappedData) - offset;
162         return {};
163     }
164 
GetMappedPointerImpl()165     void* Buffer::GetMappedPointerImpl() {
166         // The mapping offset has already been removed.
167         return mMappedData;
168     }
169 
UnmapImpl()170     void Buffer::UnmapImpl() {
171         const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
172 
173         gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
174         gl.UnmapBuffer(GL_ARRAY_BUFFER);
175         mMappedData = nullptr;
176     }
177 
DestroyImpl()178     void Buffer::DestroyImpl() {
179         BufferBase::DestroyImpl();
180         ToBackend(GetDevice())->gl.DeleteBuffers(1, &mBuffer);
181         mBuffer = 0;
182     }
183 
184 }}  // namespace dawn_native::opengl
185