BufferD3D.cpp (6102B)
1 // 2 // Copyright 2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // BufferD3D.cpp Defines common functionality between the Buffer9 and Buffer11 classes. 8 9 #include "libANGLE/renderer/d3d/BufferD3D.h" 10 11 #include "common/mathutil.h" 12 #include "common/utilities.h" 13 #include "libANGLE/renderer/d3d/IndexBuffer.h" 14 #include "libANGLE/renderer/d3d/RendererD3D.h" 15 #include "libANGLE/renderer/d3d/VertexBuffer.h" 16 17 namespace rx 18 { 19 20 unsigned int BufferD3D::mNextSerial = 1; 21 22 BufferD3D::BufferD3D(const gl::BufferState &state, BufferFactoryD3D *factory) 23 : BufferImpl(state), 24 mFactory(factory), 25 mStaticIndexBuffer(nullptr), 26 mStaticBufferCacheTotalSize(0), 27 mStaticVertexBufferOutOfDate(false), 28 mUnmodifiedDataUse(0), 29 mUsage(D3DBufferUsage::STATIC) 30 { 31 updateSerial(); 32 } 33 34 BufferD3D::~BufferD3D() 35 { 36 SafeDelete(mStaticIndexBuffer); 37 } 38 39 void BufferD3D::emptyStaticBufferCache() 40 { 41 mStaticVertexBuffers.clear(); 42 mStaticBufferCacheTotalSize = 0; 43 } 44 45 void BufferD3D::updateSerial() 46 { 47 mSerial = mNextSerial++; 48 } 49 50 void BufferD3D::updateD3DBufferUsage(const gl::Context *context, gl::BufferUsage usage) 51 { 52 switch (usage) 53 { 54 case gl::BufferUsage::StaticCopy: 55 case gl::BufferUsage::StaticDraw: 56 case gl::BufferUsage::StaticRead: 57 case gl::BufferUsage::DynamicCopy: 58 case gl::BufferUsage::DynamicRead: 59 case gl::BufferUsage::StreamCopy: 60 case gl::BufferUsage::StreamRead: 61 mUsage = D3DBufferUsage::STATIC; 62 initializeStaticData(context); 63 break; 64 65 case gl::BufferUsage::DynamicDraw: 66 case gl::BufferUsage::StreamDraw: 67 mUsage = D3DBufferUsage::DYNAMIC; 68 break; 69 default: 70 UNREACHABLE(); 71 } 72 } 73 74 void BufferD3D::initializeStaticData(const gl::Context *context) 75 { 76 if (mStaticVertexBuffers.empty()) 77 { 78 StaticVertexBufferInterface *newStaticBuffer = new StaticVertexBufferInterface(mFactory); 79 mStaticVertexBuffers.push_back( 80 std::unique_ptr<StaticVertexBufferInterface>(newStaticBuffer)); 81 } 82 if (!mStaticIndexBuffer) 83 { 84 mStaticIndexBuffer = new StaticIndexBufferInterface(mFactory); 85 } 86 } 87 88 StaticIndexBufferInterface *BufferD3D::getStaticIndexBuffer() 89 { 90 return mStaticIndexBuffer; 91 } 92 93 StaticVertexBufferInterface *BufferD3D::getStaticVertexBuffer(const gl::VertexAttribute &attribute, 94 const gl::VertexBinding &binding) 95 { 96 if (mStaticVertexBuffers.empty()) 97 { 98 // Early out if there aren't any static buffers at all 99 return nullptr; 100 } 101 102 // Early out, the attribute can be added to mStaticVertexBuffer. 103 if (mStaticVertexBuffers.size() == 1 && mStaticVertexBuffers[0]->empty()) 104 { 105 return mStaticVertexBuffers[0].get(); 106 } 107 108 // Cache size limiting: track the total allocated buffer sizes. 109 size_t currentTotalSize = 0; 110 111 // At this point, see if any of the existing static buffers contains the attribute data 112 // If there is a cached static buffer that already contains the attribute, then return it 113 for (const auto &staticBuffer : mStaticVertexBuffers) 114 { 115 if (staticBuffer->matchesAttribute(attribute, binding)) 116 { 117 return staticBuffer.get(); 118 } 119 120 currentTotalSize += staticBuffer->getBufferSize(); 121 } 122 123 // Cache size limiting: Clean-up threshold is four times the base buffer size, with a minimum. 124 ASSERT(getSize() < std::numeric_limits<size_t>::max() / 4u); 125 size_t sizeThreshold = std::max(getSize() * 4u, static_cast<size_t>(0x1000u)); 126 127 // If we're past the threshold, clear the buffer cache. Note that this will release buffers 128 // that are currenly bound, and in an edge case can even translate the same attribute twice 129 // in the same draw call. It will not delete currently bound buffers, however, because they 130 // are ref counted. 131 if (currentTotalSize > sizeThreshold) 132 { 133 emptyStaticBufferCache(); 134 } 135 136 // At this point, we must create a new static buffer for the attribute data. 137 StaticVertexBufferInterface *newStaticBuffer = new StaticVertexBufferInterface(mFactory); 138 newStaticBuffer->setAttribute(attribute, binding); 139 mStaticVertexBuffers.push_back(std::unique_ptr<StaticVertexBufferInterface>(newStaticBuffer)); 140 return newStaticBuffer; 141 } 142 143 void BufferD3D::invalidateStaticData(const gl::Context *context) 144 { 145 emptyStaticBufferCache(); 146 147 if (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0) 148 { 149 SafeDelete(mStaticIndexBuffer); 150 } 151 152 // If the buffer was created with a static usage then we recreate the static 153 // buffers so that they are populated the next time we use this buffer. 154 if (mUsage == D3DBufferUsage::STATIC) 155 { 156 initializeStaticData(context); 157 } 158 159 mUnmodifiedDataUse = 0; 160 } 161 162 // Creates static buffers if sufficient used data has been left unmodified 163 void BufferD3D::promoteStaticUsage(const gl::Context *context, size_t dataSize) 164 { 165 if (mUsage == D3DBufferUsage::DYNAMIC) 166 { 167 // Note: This is not a safe math operation. 'dataSize' can come from the app. 168 mUnmodifiedDataUse += dataSize; 169 170 if (mUnmodifiedDataUse > 3 * getSize()) 171 { 172 updateD3DBufferUsage(context, gl::BufferUsage::StaticDraw); 173 } 174 } 175 } 176 177 angle::Result BufferD3D::getIndexRange(const gl::Context *context, 178 gl::DrawElementsType type, 179 size_t offset, 180 size_t count, 181 bool primitiveRestartEnabled, 182 gl::IndexRange *outRange) 183 { 184 const uint8_t *data = nullptr; 185 ANGLE_TRY(getData(context, &data)); 186 187 *outRange = gl::ComputeIndexRange(type, data + offset, count, primitiveRestartEnabled); 188 return angle::Result::Continue; 189 } 190 191 } // namespace rx