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