Fix updates hillshade geometry (#2842)
This commit is contained in:
@@ -25,6 +25,7 @@ class PaintParameters;
|
||||
class PaintPropertyBindersBase;
|
||||
enum class RenderPass : uint8_t;
|
||||
class RenderTile;
|
||||
class SegmentBase;
|
||||
|
||||
using LayerTweakerPtr = std::shared_ptr<LayerTweaker>;
|
||||
using RenderTiles = std::shared_ptr<const std::vector<std::reference_wrapper<const RenderTile>>>;
|
||||
@@ -192,7 +193,20 @@ public:
|
||||
const gfx::VertexAttributeArrayPtr& getVertexAttributes() const noexcept { return vertexAttributes; }
|
||||
|
||||
/// Set vertex attribute array
|
||||
void setVertexAttributes(gfx::VertexAttributeArrayPtr value) noexcept { vertexAttributes = std::move(value); }
|
||||
void setVertexAttributes(gfx::VertexAttributeArrayPtr value) noexcept {
|
||||
vertexAttributes = std::move(value);
|
||||
// The attribute bindings need to be rebuilt, we can't rely on the update
|
||||
// time check as these new values may not have been modified recently.
|
||||
attributeUpdateTime.reset();
|
||||
}
|
||||
|
||||
/// Update vertices, indices, and segments
|
||||
virtual void updateVertexAttributes(gfx::VertexAttributeArrayPtr,
|
||||
std::size_t vertexCount,
|
||||
gfx::DrawMode,
|
||||
gfx::IndexVectorBasePtr,
|
||||
const SegmentBase* segments,
|
||||
std::size_t segmentCount) = 0;
|
||||
|
||||
/// Get the instance attributes
|
||||
const gfx::VertexAttributeArrayPtr& getInstanceAttributes() const noexcept { return instanceAttributes; }
|
||||
@@ -261,6 +275,7 @@ public:
|
||||
void setRenderTile(Immutable<std::vector<RenderTile>>, const RenderTile*);
|
||||
|
||||
const std::chrono::duration<double> createTime = util::MonotonicTimer::now();
|
||||
std::optional<std::chrono::duration<double>> getAttributeUpdateTime() const { return attributeUpdateTime; }
|
||||
|
||||
protected:
|
||||
bool enabled = true;
|
||||
@@ -282,7 +297,7 @@ protected:
|
||||
UniqueDrawableData drawableData{};
|
||||
gfx::VertexAttributeArrayPtr vertexAttributes;
|
||||
gfx::VertexAttributeArrayPtr instanceAttributes;
|
||||
std::chrono::duration<double> attributeUpdateTime = util::MonotonicTimer::now();
|
||||
std::optional<std::chrono::duration<double>> attributeUpdateTime;
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
|
||||
@@ -48,6 +48,13 @@ public:
|
||||
|
||||
void upload(gfx::UploadPass&);
|
||||
|
||||
void updateVertexAttributes(gfx::VertexAttributeArrayPtr,
|
||||
std::size_t vertexCount,
|
||||
gfx::DrawMode,
|
||||
gfx::IndexVectorBasePtr,
|
||||
const SegmentBase* segments,
|
||||
std::size_t segmentCount) override;
|
||||
|
||||
protected:
|
||||
class Impl;
|
||||
const std::unique_ptr<Impl> impl;
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
|
||||
static const std::vector<std::uint8_t>& getRaw(gfx::VertexAttribute& attr,
|
||||
platform::GLenum,
|
||||
std::chrono::duration<double> lastUpdate);
|
||||
std::optional<std::chrono::duration<double>> lastUpdate);
|
||||
|
||||
private:
|
||||
static int getSize(platform::GLenum glType);
|
||||
|
||||
@@ -130,9 +130,6 @@ public:
|
||||
std::size_t size,
|
||||
bool persistent) override;
|
||||
|
||||
/// Get an empty buffer to act as a placeholder
|
||||
const BufferResource& getEmptyBuffer();
|
||||
|
||||
/// Get a reusable buffer containing the standard fixed tile vertices (+/- `util::EXTENT`)
|
||||
const BufferResource& getTileVertexBuffer();
|
||||
|
||||
|
||||
@@ -57,6 +57,13 @@ public:
|
||||
void setSubLayerIndex(int32_t) override;
|
||||
void setDepthType(gfx::DepthMaskType) override;
|
||||
|
||||
void updateVertexAttributes(gfx::VertexAttributeArrayPtr,
|
||||
std::size_t vertexCount,
|
||||
gfx::DrawMode,
|
||||
gfx::IndexVectorBasePtr,
|
||||
const SegmentBase* segments,
|
||||
std::size_t segmentCount) override;
|
||||
|
||||
protected:
|
||||
// For testing only.
|
||||
Drawable(std::unique_ptr<Impl>);
|
||||
|
||||
@@ -56,7 +56,9 @@ public:
|
||||
|
||||
void updateResource(BufferResource&, const void* data, std::size_t size);
|
||||
|
||||
const gfx::UniqueVertexBufferResource& getBuffer(const gfx::VertexVectorBasePtr&, gfx::BufferUsageType);
|
||||
const gfx::UniqueVertexBufferResource& getBuffer(const gfx::VertexVectorBasePtr&,
|
||||
gfx::BufferUsageType,
|
||||
bool forceUpdate);
|
||||
|
||||
gfx::AttributeBindingArray buildAttributeBindings(
|
||||
const std::size_t vertexCount,
|
||||
@@ -66,7 +68,7 @@ public:
|
||||
const gfx::VertexAttributeArray& defaults,
|
||||
const gfx::VertexAttributeArray& overrides,
|
||||
gfx::BufferUsageType,
|
||||
const std::chrono::duration<double> lastUpdate,
|
||||
const std::optional<std::chrono::duration<double>> lastUpdate,
|
||||
/*out*/ std::vector<std::unique_ptr<gfx::VertexBufferResource>>& outBuffers) override;
|
||||
|
||||
std::unique_ptr<gfx::TextureResource> createTextureResource(Size,
|
||||
|
||||
@@ -22,7 +22,8 @@ public:
|
||||
|
||||
static const gfx::UniqueVertexBufferResource& getBuffer(gfx::VertexAttribute&,
|
||||
UploadPass&,
|
||||
const gfx::BufferUsageType);
|
||||
const gfx::BufferUsageType,
|
||||
bool forceUpdate);
|
||||
};
|
||||
|
||||
/// Stores a collection of vertex attributes by name
|
||||
|
||||
@@ -44,6 +44,13 @@ public:
|
||||
void setLineWidth(int32_t value) override;
|
||||
void setCullFaceMode(const gfx::CullFaceMode&) override;
|
||||
|
||||
void updateVertexAttributes(gfx::VertexAttributeArrayPtr,
|
||||
std::size_t vertexCount,
|
||||
gfx::DrawMode,
|
||||
gfx::IndexVectorBasePtr,
|
||||
const SegmentBase* segments,
|
||||
std::size_t segmentCount) override;
|
||||
|
||||
protected:
|
||||
void buildVulkanInputBindings() noexcept;
|
||||
|
||||
|
||||
@@ -51,7 +51,9 @@ public:
|
||||
bool persistent) override;
|
||||
void updateIndexBufferResource(gfx::IndexBufferResource&, const void* data, std::size_t size) override;
|
||||
|
||||
const gfx::UniqueVertexBufferResource& getBuffer(const gfx::VertexVectorBasePtr&, gfx::BufferUsageType);
|
||||
const gfx::UniqueVertexBufferResource& getBuffer(const gfx::VertexVectorBasePtr&,
|
||||
gfx::BufferUsageType,
|
||||
bool forceUpdate);
|
||||
|
||||
gfx::AttributeBindingArray buildAttributeBindings(
|
||||
const std::size_t vertexCount,
|
||||
@@ -61,7 +63,7 @@ public:
|
||||
const gfx::VertexAttributeArray& defaults,
|
||||
const gfx::VertexAttributeArray& overrides,
|
||||
gfx::BufferUsageType,
|
||||
const std::chrono::duration<double> lastUpdate,
|
||||
const std::optional<std::chrono::duration<double>> lastUpdate,
|
||||
/*out*/ std::vector<std::unique_ptr<gfx::VertexBufferResource>>& outBuffers) override;
|
||||
|
||||
std::unique_ptr<gfx::TextureResource> createTextureResource(Size,
|
||||
|
||||
@@ -23,7 +23,8 @@ public:
|
||||
|
||||
static const gfx::UniqueVertexBufferResource& getBuffer(gfx::VertexAttribute&,
|
||||
UploadPass&,
|
||||
const gfx::BufferUsageType);
|
||||
const gfx::BufferUsageType,
|
||||
bool forceUpdate);
|
||||
};
|
||||
|
||||
/// Stores a collection of vertex attributes by name
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
const gfx::VertexAttributeArray& defaults,
|
||||
const gfx::VertexAttributeArray& overrides,
|
||||
gfx::BufferUsageType,
|
||||
const std::chrono::duration<double> lastUpdate,
|
||||
const std::optional<std::chrono::duration<double>> lastUpdate,
|
||||
/*out*/ std::vector<std::unique_ptr<gfx::VertexBufferResource>>& outBuffers) = 0;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -86,6 +86,36 @@ void DrawableGL::setIndexData(gfx::IndexVectorBasePtr indexes, std::vector<Uniqu
|
||||
impl->segments = std::move(segments);
|
||||
}
|
||||
|
||||
void DrawableGL::updateVertexAttributes(gfx::VertexAttributeArrayPtr vertices,
|
||||
std::size_t vertexCount,
|
||||
gfx::DrawMode mode,
|
||||
gfx::IndexVectorBasePtr indexes,
|
||||
const SegmentBase* segments,
|
||||
std::size_t segmentCount) {
|
||||
gfx::Drawable::setVertexAttributes(std::move(vertices));
|
||||
impl->vertexCount = vertexCount;
|
||||
|
||||
std::vector<std::unique_ptr<Drawable::DrawSegment>> drawSegs;
|
||||
drawSegs.reserve(segmentCount);
|
||||
for (std::size_t i = 0; i < segmentCount; ++i) {
|
||||
const auto& seg = segments[i];
|
||||
auto segCopy = SegmentBase{
|
||||
// no copy constructor
|
||||
seg.vertexOffset,
|
||||
seg.indexOffset,
|
||||
seg.vertexLength,
|
||||
seg.indexLength,
|
||||
seg.sortKey,
|
||||
};
|
||||
auto drawSeg = std::make_unique<DrawableGL::DrawSegmentGL>(
|
||||
mode, std::move(segCopy), VertexArray{{nullptr, false}});
|
||||
drawSegs.push_back(std::move(drawSeg));
|
||||
}
|
||||
|
||||
impl->indexes = std::move(indexes);
|
||||
impl->segments = std::move(drawSegs);
|
||||
}
|
||||
|
||||
void DrawableGL::setVertices(std::vector<uint8_t>&& data, std::size_t count, gfx::AttributeDataType type_) {
|
||||
impl->vertexData = std::move(data);
|
||||
impl->vertexCount = count;
|
||||
@@ -166,7 +196,8 @@ void DrawableGL::upload(gfx::UploadPass& uploadPass) {
|
||||
if (impl->indexes) {
|
||||
impl->indexes->updateModified();
|
||||
}
|
||||
if (impl->indexes && (!impl->indexes->getBuffer() || impl->indexes->isModifiedAfter(attributeUpdateTime))) {
|
||||
if (impl->indexes &&
|
||||
(!impl->indexes->getBuffer() || !attributeUpdateTime || impl->indexes->isModifiedAfter(*attributeUpdateTime))) {
|
||||
MLN_TRACE_ZONE(build indexes);
|
||||
auto indexBufferResource{
|
||||
uploadPass.createIndexBufferResource(impl->indexes->data(), impl->indexes->bytes(), usage)};
|
||||
@@ -178,7 +209,7 @@ void DrawableGL::upload(gfx::UploadPass& uploadPass) {
|
||||
|
||||
// Build the vertex attributes and bindings, if necessary
|
||||
if (impl->attributeBindings.empty() ||
|
||||
(vertexAttributes && vertexAttributes->isModifiedAfter(attributeUpdateTime))) {
|
||||
(vertexAttributes && (!attributeUpdateTime || vertexAttributes->isModifiedAfter(*attributeUpdateTime)))) {
|
||||
MLN_TRACE_ZONE(build attributes);
|
||||
|
||||
// Apply drawable values to shader defaults
|
||||
|
||||
@@ -193,7 +193,7 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings(
|
||||
const gfx::VertexAttributeArray& defaults,
|
||||
const gfx::VertexAttributeArray& overrides,
|
||||
const gfx::BufferUsageType usage,
|
||||
const std::chrono::duration<double> lastUpdate,
|
||||
const std::optional<std::chrono::duration<double>> lastUpdate,
|
||||
/*out*/ std::vector<std::unique_ptr<gfx::VertexBufferResource>>& outBuffers) {
|
||||
MLN_TRACE_FUNC();
|
||||
AttributeBindingArray bindings;
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
const gfx::VertexAttributeArray& defaults,
|
||||
const gfx::VertexAttributeArray& overrides,
|
||||
gfx::BufferUsageType,
|
||||
const std::chrono::duration<double> lastUpdate,
|
||||
const std::optional<std::chrono::duration<double>> lastUpdate,
|
||||
/*out*/ std::vector<std::unique_ptr<gfx::VertexBufferResource>>& outBuffers) override;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -155,11 +155,11 @@ std::size_t VertexAttributeGL::getStride() const {
|
||||
|
||||
const std::vector<std::uint8_t>& VertexAttributeGL::getRaw(gfx::VertexAttribute& attr,
|
||||
platform::GLenum type,
|
||||
std::chrono::duration<double> lastUpdate) {
|
||||
std::optional<std::chrono::duration<double>> lastUpdate) {
|
||||
const auto count = attr.getCount();
|
||||
const auto stride_ = getStride(type);
|
||||
auto& rawData = attr.getRawData();
|
||||
if (attr.isModifiedAfter(lastUpdate) || rawData.size() != count * stride_) {
|
||||
if (!lastUpdate || attr.isModifiedAfter(*lastUpdate) || rawData.size() != count * stride_) {
|
||||
rawData.resize(stride_ * count);
|
||||
|
||||
if (!rawData.empty()) {
|
||||
|
||||
@@ -241,13 +241,6 @@ bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer,
|
||||
}
|
||||
}
|
||||
|
||||
const BufferResource& Context::getEmptyBuffer() {
|
||||
if (!emptyBuffer) {
|
||||
emptyBuffer.emplace(const_cast<Context&>(*this), nullptr, 0, MTL::ResourceStorageModeShared, false, false);
|
||||
}
|
||||
return *emptyBuffer;
|
||||
}
|
||||
|
||||
const BufferResource& Context::getTileVertexBuffer() {
|
||||
if (!tileVertexBuffer) {
|
||||
const auto vertices = RenderStaticData::tileVertices();
|
||||
|
||||
@@ -191,13 +191,13 @@ void Drawable::draw(PaintParameters& parameters) const {
|
||||
bindUniformBuffers(renderPass);
|
||||
bindTextures(renderPass);
|
||||
|
||||
if (!impl->indexes->getBuffer() || impl->indexes->isModifiedAfter(attributeUpdateTime)) {
|
||||
if (!impl->indexes->getBuffer() || !attributeUpdateTime || impl->indexes->isModifiedAfter(*attributeUpdateTime)) {
|
||||
assert(!"Index buffer not uploaded");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* indexBuffer = getMetalBuffer(impl->indexes);
|
||||
if (!indexBuffer || impl->indexes->isModifiedAfter(attributeUpdateTime)) {
|
||||
if (!indexBuffer || !attributeUpdateTime || impl->indexes->isModifiedAfter(*attributeUpdateTime)) {
|
||||
assert(!"Index buffer not uploaded");
|
||||
return;
|
||||
}
|
||||
@@ -341,6 +341,34 @@ void Drawable::setVertices(std::vector<uint8_t>&& data, std::size_t count, gfx::
|
||||
}
|
||||
}
|
||||
|
||||
void Drawable::updateVertexAttributes(gfx::VertexAttributeArrayPtr vertices,
|
||||
std::size_t vertexCount,
|
||||
gfx::DrawMode mode,
|
||||
gfx::IndexVectorBasePtr indexes,
|
||||
const SegmentBase* segments,
|
||||
std::size_t segmentCount) {
|
||||
gfx::Drawable::setVertexAttributes(std::move(vertices));
|
||||
impl->vertexCount = vertexCount;
|
||||
|
||||
std::vector<UniqueDrawSegment> drawSegs;
|
||||
drawSegs.reserve(segmentCount);
|
||||
for (std::size_t i = 0; i < segmentCount; ++i) {
|
||||
const auto& seg = segments[i];
|
||||
auto segCopy = SegmentBase{
|
||||
// no copy constructor
|
||||
seg.vertexOffset,
|
||||
seg.indexOffset,
|
||||
seg.vertexLength,
|
||||
seg.indexLength,
|
||||
seg.sortKey,
|
||||
};
|
||||
drawSegs.push_back(std::make_unique<Drawable::DrawSegment>(mode, std::move(segCopy)));
|
||||
}
|
||||
|
||||
impl->indexes = std::move(indexes);
|
||||
impl->segments = std::move(drawSegs);
|
||||
}
|
||||
|
||||
const gfx::UniformBufferArray& Drawable::getUniformBuffers() const {
|
||||
return impl->uniformBuffers;
|
||||
}
|
||||
@@ -363,9 +391,6 @@ void Drawable::bindAttributes(RenderPass& renderPass) const noexcept {
|
||||
if (buffer && buffer->get()) {
|
||||
assert(binding->vertexStride * impl->vertexCount <= getBufferSize(binding->vertexBufferResource));
|
||||
renderPass.bindVertex(buffer->get(), /*offset=*/0, attributeIndex);
|
||||
} else {
|
||||
auto& context = renderPass.getCommandEncoder().getContext();
|
||||
renderPass.bindVertex(context.getEmptyBuffer(), /*offset=*/0, attributeIndex);
|
||||
}
|
||||
attributeIndex += 1;
|
||||
}
|
||||
@@ -380,9 +405,6 @@ void Drawable::bindInstanceAttributes(RenderPass& renderPass) const noexcept {
|
||||
const auto* buffer = static_cast<const mtl::VertexBufferResource*>(binding->vertexBufferResource);
|
||||
if (buffer && buffer->get()) {
|
||||
renderPass.bindVertex(buffer->get(), /*offset=*/0, attributeIndex);
|
||||
} else {
|
||||
auto& context = renderPass.getCommandEncoder().getContext();
|
||||
renderPass.bindVertex(context.getEmptyBuffer(), /*offset=*/0, attributeIndex);
|
||||
}
|
||||
}
|
||||
attributeIndex += 1;
|
||||
@@ -530,13 +552,13 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
||||
|
||||
// We need either raw index data or a buffer already created from them.
|
||||
// We can have a buffer and no indexes, but only if it's not marked dirty.
|
||||
if (!impl->indexes || (impl->indexes->empty() &&
|
||||
(!impl->indexes->getBuffer() || impl->indexes->isModifiedAfter(attributeUpdateTime)))) {
|
||||
if (!impl->indexes || (impl->indexes->empty() && (!impl->indexes->getBuffer() || !attributeUpdateTime ||
|
||||
impl->indexes->isModifiedAfter(*attributeUpdateTime)))) {
|
||||
assert(!"Missing index data");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!impl->indexes->getBuffer() || impl->indexes->isModifiedAfter(attributeUpdateTime)) {
|
||||
if (!impl->indexes->getBuffer() || !attributeUpdateTime || impl->indexes->isModifiedAfter(*attributeUpdateTime)) {
|
||||
// Create or update a buffer for the index data. We don't update any
|
||||
// existing buffer because it may still be in use by the previous frame.
|
||||
auto indexBufferResource{uploadPass.createIndexBufferResource(
|
||||
@@ -548,8 +570,8 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
||||
impl->indexes->setBuffer(std::move(buffer));
|
||||
}
|
||||
|
||||
const bool buildAttribs = !vertexAttributes || vertexAttributes->isModifiedAfter(attributeUpdateTime) ||
|
||||
!impl->vertexDesc;
|
||||
const bool buildAttribs = !impl->vertexDesc || !vertexAttributes || !attributeUpdateTime ||
|
||||
vertexAttributes->isModifiedAfter(*attributeUpdateTime);
|
||||
|
||||
if (buildAttribs) {
|
||||
#if !defined(NDEBUG)
|
||||
@@ -630,7 +652,8 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
||||
}
|
||||
|
||||
// build instance buffer
|
||||
const bool buildInstanceBuffer = (instanceAttributes && instanceAttributes->isModifiedAfter(attributeUpdateTime));
|
||||
const bool buildInstanceBuffer =
|
||||
(instanceAttributes && (!attributeUpdateTime || instanceAttributes->isModifiedAfter(*attributeUpdateTime)));
|
||||
|
||||
if (buildInstanceBuffer) {
|
||||
// Build instance attribute buffers
|
||||
|
||||
@@ -119,7 +119,8 @@ namespace {
|
||||
const std::unique_ptr<gfx::VertexBufferResource> noBuffer;
|
||||
}
|
||||
const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVectorBasePtr& vec,
|
||||
const gfx::BufferUsageType usage) {
|
||||
const gfx::BufferUsageType usage,
|
||||
bool forceUpdate) {
|
||||
if (vec) {
|
||||
const auto* rawBufPtr = vec->getRawData();
|
||||
const auto rawBufSize = vec->getRawCount() * vec->getRawSize();
|
||||
@@ -131,7 +132,7 @@ const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVe
|
||||
// If the already-allocated buffer is large enough, we can re-use it
|
||||
if (rawBufSize <= resource.getSizeInBytes()) {
|
||||
// If the source changed, update the buffer contents
|
||||
if (vec->isModifiedAfter(resource.getLastUpdated())) {
|
||||
if (forceUpdate || vec->isModifiedAfter(resource.getLastUpdated())) {
|
||||
updateVertexBufferResource(resource, rawBufPtr, rawBufSize);
|
||||
resource.setLastUpdated(vec->getLastModified());
|
||||
}
|
||||
@@ -157,7 +158,7 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings(
|
||||
const gfx::VertexAttributeArray& defaults,
|
||||
const gfx::VertexAttributeArray& overrides,
|
||||
const gfx::BufferUsageType usage,
|
||||
const std::chrono::duration<double> /*lastUpdate*/,
|
||||
const std::optional<std::chrono::duration<double>> lastUpdate,
|
||||
/*out*/ std::vector<std::unique_ptr<gfx::VertexBufferResource>>& outBuffers) {
|
||||
MLN_TRACE_FUNC();
|
||||
|
||||
@@ -191,7 +192,7 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings(
|
||||
}
|
||||
|
||||
// If the attribute references data shared with a bucket, get the corresponding buffer.
|
||||
if (const auto& buffer_ = getBuffer(effectiveAttr.getSharedRawData(), usage)) {
|
||||
if (const auto& buffer_ = getBuffer(effectiveAttr.getSharedRawData(), usage, !lastUpdate)) {
|
||||
assert(effectiveAttr.getSharedStride() * effectiveAttr.getSharedVertexOffset() <
|
||||
effectiveAttr.getSharedRawData()->getRawSize() * effectiveAttr.getSharedRawData()->getRawCount());
|
||||
|
||||
@@ -207,7 +208,8 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings(
|
||||
assert(effectiveAttr.getStride() > 0);
|
||||
|
||||
// Otherwise, turn the data managed by the attribute into a buffer.
|
||||
if (const auto& buffer_ = VertexAttribute::getBuffer(effectiveAttr, *this, gfx::BufferUsageType::StaticDraw)) {
|
||||
if (const auto& buffer_ = VertexAttribute::getBuffer(
|
||||
effectiveAttr, *this, gfx::BufferUsageType::StaticDraw, !lastUpdate)) {
|
||||
bindings[index] = {
|
||||
/*.attribute = */ {effectiveAttr.getDataType(), /*offset=*/0},
|
||||
/*.vertexStride = */ static_cast<uint32_t>(effectiveAttr.getStride()),
|
||||
|
||||
@@ -14,11 +14,12 @@ namespace mtl {
|
||||
|
||||
const gfx::UniqueVertexBufferResource& VertexAttribute::getBuffer(gfx::VertexAttribute& attrib_,
|
||||
UploadPass& uploadPass,
|
||||
const gfx::BufferUsageType usage) {
|
||||
const gfx::BufferUsageType usage,
|
||||
bool forceUpdate) {
|
||||
if (!attrib_.getBuffer()) {
|
||||
auto& attrib = static_cast<VertexAttribute&>(attrib_);
|
||||
if (attrib.sharedRawData) {
|
||||
return uploadPass.getBuffer(attrib.sharedRawData, usage);
|
||||
return uploadPass.getBuffer(attrib.sharedRawData, usage, forceUpdate);
|
||||
} else {
|
||||
if (!attrib.rawData.empty()) {
|
||||
auto buffer = uploadPass.createVertexBufferResource(
|
||||
|
||||
@@ -56,6 +56,9 @@ void HillshadeBucket::clear() {
|
||||
vertices.clear();
|
||||
indices.clear();
|
||||
|
||||
vertices.updateModified();
|
||||
indices.updateModified();
|
||||
|
||||
uploaded = false;
|
||||
}
|
||||
|
||||
@@ -116,6 +119,9 @@ void HillshadeBucket::setMask(TileMask&& mask_) {
|
||||
segment.vertexLength += vertexLength;
|
||||
segment.indexLength += 6;
|
||||
}
|
||||
|
||||
vertices.updateModified();
|
||||
indices.updateModified();
|
||||
}
|
||||
|
||||
bool HillshadeBucket::hasData() const {
|
||||
|
||||
@@ -49,7 +49,10 @@ public:
|
||||
std::shared_ptr<VertexVector> sharedVertices = std::make_shared<VertexVector>();
|
||||
VertexVector& vertices = *sharedVertices;
|
||||
|
||||
gfx::IndexVector<gfx::Triangles> indices;
|
||||
using IndexVector = gfx::IndexVector<gfx::Triangles>;
|
||||
std::shared_ptr<IndexVector> sharedIndices = std::make_shared<IndexVector>();
|
||||
IndexVector& indices = *sharedIndices;
|
||||
|
||||
SegmentVector<HillshadeAttributes> segments;
|
||||
|
||||
#if MLN_LEGACY_RENDERER
|
||||
|
||||
@@ -46,6 +46,9 @@ void RasterBucket::clear() {
|
||||
vertices.clear();
|
||||
indices.clear();
|
||||
|
||||
vertices.updateModified();
|
||||
indices.updateModified();
|
||||
|
||||
uploaded = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -351,6 +351,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
|
||||
const auto layerPrefix = getID() + "/";
|
||||
constexpr auto renderPass = RenderPass::Translucent;
|
||||
constexpr auto lineWidth = 2.0f;
|
||||
|
||||
const auto commonInit = [&](gfx::DrawableBuilder& builder) {
|
||||
builder.setCullFaceMode(gfx::CullFaceMode::disabled());
|
||||
@@ -415,7 +416,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
vertexAttrs->readDataDrivenPaintProperties<FillColor, FillOpacity, FillOutlineColor, FillPattern>(
|
||||
binders, evaluated, propertiesAsUniforms, idFillColorVertexAttribute);
|
||||
|
||||
const auto vertexCount = bucket.vertices.elements();
|
||||
const auto fillVertexCount = bucket.vertices.elements();
|
||||
if (const auto& attr = vertexAttrs->set(idFillPosVertexAttribute)) {
|
||||
attr->setSharedRawData(bucket.sharedVertices,
|
||||
offsetof(FillLayoutVertex, a1),
|
||||
@@ -424,27 +425,91 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
|
||||
#if MLN_TRIANGULATE_FILL_OUTLINES
|
||||
const auto lineVertexCount = bucket.lineVertices.elements();
|
||||
const auto getTriangulatedAttributes = [&]() {
|
||||
auto attrs = context.createVertexAttributeArray();
|
||||
if (const auto& attr = attrs->set(idLinePosNormalVertexAttribute)) {
|
||||
attr->setSharedRawData(bucket.sharedLineVertices,
|
||||
offsetof(LineLayoutVertex, a1),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(LineLayoutVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
if (const auto& attr = attrs->set(idLineDataVertexAttribute)) {
|
||||
attr->setSharedRawData(bucket.sharedLineVertices,
|
||||
offsetof(LineLayoutVertex, a2),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(LineLayoutVertex),
|
||||
gfx::AttributeDataType::UByte4);
|
||||
}
|
||||
return attrs;
|
||||
};
|
||||
#endif
|
||||
|
||||
// If we already have drawables for this tile, update them.
|
||||
auto updateExisting = [&](gfx::Drawable& drawable) {
|
||||
if (drawable.getLayerTweaker() != layerTweaker) {
|
||||
// This drawable was produced on a previous style/bucket, and should not be updated.
|
||||
return false;
|
||||
}
|
||||
drawable.setVertexAttributes(vertexAttrs);
|
||||
|
||||
switch (static_cast<FillVariant>(drawable.getType())) {
|
||||
case FillVariant::Fill:
|
||||
case FillVariant::FillPattern:
|
||||
drawable.updateVertexAttributes(vertexAttrs,
|
||||
fillVertexCount,
|
||||
gfx::Triangles(),
|
||||
bucket.sharedTriangles,
|
||||
bucket.triangleSegments.data(),
|
||||
bucket.triangleSegments.size());
|
||||
break;
|
||||
case FillVariant::FillOutline:
|
||||
case FillVariant::FillOutlinePattern:
|
||||
drawable.updateVertexAttributes(vertexAttrs,
|
||||
fillVertexCount,
|
||||
gfx::Lines(lineWidth),
|
||||
bucket.sharedBasicLineIndexes,
|
||||
bucket.basicLineSegments.data(),
|
||||
bucket.basicLineSegments.size());
|
||||
break;
|
||||
#if MLN_TRIANGULATE_FILL_OUTLINES
|
||||
case FillVariant::FillOutlineTriangulated:
|
||||
if (const auto updated = drawable.getAttributeUpdateTime();
|
||||
!updated || bucket.lineVertices.getLastModified() > *updated) {
|
||||
drawable.updateVertexAttributes(getTriangulatedAttributes(),
|
||||
lineVertexCount,
|
||||
gfx::Triangles(),
|
||||
bucket.sharedLineIndexes,
|
||||
bucket.lineSegments.data(),
|
||||
bucket.lineSegments.size());
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
Log::Error(Event::General, "Invalid fill type " + util::toString(drawable.getType()));
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
if (updateTile(renderPass, tileID, std::move(updateExisting))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto addDrawable = [&](std::unique_ptr<gfx::Drawable> drawable, FillVariant type) {
|
||||
drawable->setTileID(tileID);
|
||||
drawable->setType(static_cast<size_t>(type));
|
||||
drawable->setLayerTweaker(layerTweaker);
|
||||
drawable->setBinders(renderData->bucket, &binders);
|
||||
drawable->setRenderTile(renderTilesOwner, &tile);
|
||||
fillTileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
|
||||
++stats.drawablesAdded;
|
||||
const auto finish = [&](gfx::DrawableBuilder& builder, FillVariant type) {
|
||||
builder.flush(context);
|
||||
|
||||
for (auto& drawable : builder.clearDrawables()) {
|
||||
drawable->setTileID(tileID);
|
||||
drawable->setType(static_cast<size_t>(type));
|
||||
drawable->setLayerTweaker(layerTweaker);
|
||||
drawable->setBinders(renderData->bucket, &binders);
|
||||
drawable->setRenderTile(renderTilesOwner, &tile);
|
||||
fillTileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
|
||||
++stats.drawablesAdded;
|
||||
}
|
||||
};
|
||||
|
||||
// Outline always occurs in translucent pass, defaults to fill color
|
||||
@@ -475,36 +540,15 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
: nullptr;
|
||||
|
||||
auto createOutlineTriangulated = [&](auto& builder) {
|
||||
if (doOutline && builder && bucket.sharedLineIndexes->elements()) {
|
||||
if (doOutline && builder && lineVertexCount) {
|
||||
builder->setShader(outlineTriangulatedShader);
|
||||
builder->setRawVertices({}, bucket.lineVertices.elements(), gfx::AttributeDataType::Short2);
|
||||
|
||||
auto attrs = context.createVertexAttributeArray();
|
||||
if (const auto& attr = attrs->set(idLinePosNormalVertexAttribute)) {
|
||||
attr->setSharedRawData(bucket.sharedLineVertices,
|
||||
offsetof(LineLayoutVertex, a1),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(LineLayoutVertex),
|
||||
gfx::AttributeDataType::Short2);
|
||||
}
|
||||
if (const auto& attr = attrs->set(idLineDataVertexAttribute)) {
|
||||
attr->setSharedRawData(bucket.sharedLineVertices,
|
||||
offsetof(LineLayoutVertex, a2),
|
||||
/*vertexOffset=*/0,
|
||||
sizeof(LineLayoutVertex),
|
||||
gfx::AttributeDataType::UByte4);
|
||||
}
|
||||
builder->setVertexAttributes(std::move(attrs));
|
||||
|
||||
builder->setRawVertices({}, lineVertexCount, gfx::AttributeDataType::Short2);
|
||||
builder->setVertexAttributes(getTriangulatedAttributes());
|
||||
builder->setSegments(gfx::Triangles(),
|
||||
bucket.sharedLineIndexes,
|
||||
bucket.lineSegments.data(),
|
||||
bucket.lineSegments.size());
|
||||
|
||||
builder->flush(context);
|
||||
for (auto& drawable : builder->clearDrawables()) {
|
||||
addDrawable(std::move(drawable), FillVariant::FillOutlineTriangulated);
|
||||
}
|
||||
finish(*builder, FillVariant::FillOutlineTriangulated);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -531,7 +575,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
if (auto builder = context.createDrawableBuilder(layerPrefix + "fill-outline")) {
|
||||
commonInit(*builder);
|
||||
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
|
||||
builder->setLineWidth(2.0f);
|
||||
builder->setLineWidth(lineWidth);
|
||||
builder->setSubLayerIndex(unevaluated.get<FillOutlineColor>().isUndefined() ? 2 : 0);
|
||||
builder->setColorMode(gfx::ColorMode::alphaBlended());
|
||||
builder->setRenderPass(RenderPass::Translucent);
|
||||
@@ -539,32 +583,20 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
}
|
||||
}
|
||||
|
||||
const auto finish = [&](gfx::DrawableBuilder& builder, FillVariant type) {
|
||||
builder.flush(context);
|
||||
|
||||
for (auto& drawable : builder.clearDrawables()) {
|
||||
addDrawable(std::move(drawable), type);
|
||||
}
|
||||
};
|
||||
|
||||
if (fillBuilder && bucket.sharedTriangles->elements()) {
|
||||
fillBuilder->setShader(fillShader);
|
||||
#if MLN_TRIANGULATE_FILL_OUTLINES
|
||||
if (doOutline && dataDrivenOutline && outlineBuilder) {
|
||||
fillBuilder->setVertexAttributes(vertexAttrs);
|
||||
outlineBuilder->setVertexAttributes(std::move(vertexAttrs));
|
||||
} else {
|
||||
fillBuilder->setVertexAttributes(std::move(vertexAttrs));
|
||||
outlineBuilder->setVertexAttributes(vertexAttrs);
|
||||
}
|
||||
#else
|
||||
if (doOutline && outlineBuilder) {
|
||||
fillBuilder->setVertexAttributes(vertexAttrs);
|
||||
outlineBuilder->setVertexAttributes(std::move(vertexAttrs));
|
||||
} else {
|
||||
fillBuilder->setVertexAttributes(std::move(vertexAttrs));
|
||||
outlineBuilder->setVertexAttributes(vertexAttrs);
|
||||
}
|
||||
#endif
|
||||
fillBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
|
||||
fillBuilder->setVertexAttributes(std::move(vertexAttrs));
|
||||
|
||||
fillBuilder->setRawVertices({}, fillVertexCount, gfx::AttributeDataType::Short2);
|
||||
fillBuilder->setSegments(gfx::Triangles(),
|
||||
bucket.sharedTriangles,
|
||||
bucket.triangleSegments.data(),
|
||||
@@ -580,8 +612,8 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
} else {
|
||||
if (bucket.sharedBasicLineIndexes->elements()) {
|
||||
outlineBuilder->setShader(outlineShader);
|
||||
outlineBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
|
||||
outlineBuilder->setSegments(gfx::Lines(2),
|
||||
outlineBuilder->setRawVertices({}, fillVertexCount, gfx::AttributeDataType::Short2);
|
||||
outlineBuilder->setSegments(gfx::Lines(lineWidth),
|
||||
bucket.sharedBasicLineIndexes,
|
||||
bucket.basicLineSegments.data(),
|
||||
bucket.basicLineSegments.size());
|
||||
@@ -592,8 +624,8 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
#else
|
||||
if (doOutline && outlineBuilder && bucket.sharedBasicLineIndexes->elements()) {
|
||||
outlineBuilder->setShader(outlineShader);
|
||||
outlineBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
|
||||
outlineBuilder->setSegments(gfx::Lines(2),
|
||||
outlineBuilder->setRawVertices({}, fillVertexCount, gfx::AttributeDataType::Short2);
|
||||
outlineBuilder->setSegments(gfx::Lines(lineWidth),
|
||||
bucket.sharedBasicLineIndexes,
|
||||
bucket.basicLineSegments.data(),
|
||||
bucket.basicLineSegments.size());
|
||||
@@ -632,7 +664,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
if (auto builder = context.createDrawableBuilder(layerPrefix + "fill-outline-pattern")) {
|
||||
commonInit(*builder);
|
||||
builder->setShader(outlineShader);
|
||||
builder->setLineWidth(2.0f);
|
||||
builder->setLineWidth(lineWidth);
|
||||
builder->setDepthType(gfx::DepthMaskType::ReadOnly);
|
||||
builder->setColorMode(gfx::ColorMode::alphaBlended());
|
||||
builder->setSubLayerIndex(2);
|
||||
@@ -650,24 +682,14 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
outlinePatternBuilder->addTweaker(getAtlasTweaker());
|
||||
}
|
||||
|
||||
const auto finish = [&](gfx::DrawableBuilder& builder, FillVariant type) {
|
||||
builder.flush(context);
|
||||
|
||||
for (auto& drawable : builder.clearDrawables()) {
|
||||
addDrawable(std::move(drawable), type);
|
||||
}
|
||||
};
|
||||
|
||||
if (patternBuilder && bucket.sharedTriangles->elements()) {
|
||||
patternBuilder->setShader(fillShader);
|
||||
patternBuilder->setRenderPass(renderPass);
|
||||
if (doOutline && outlinePatternBuilder) {
|
||||
patternBuilder->setVertexAttributes(vertexAttrs);
|
||||
outlinePatternBuilder->setVertexAttributes(std::move(vertexAttrs));
|
||||
} else {
|
||||
patternBuilder->setVertexAttributes(std::move(vertexAttrs));
|
||||
outlinePatternBuilder->setVertexAttributes(vertexAttrs);
|
||||
}
|
||||
patternBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
|
||||
patternBuilder->setVertexAttributes(std::move(vertexAttrs));
|
||||
patternBuilder->setRawVertices({}, fillVertexCount, gfx::AttributeDataType::Short2);
|
||||
patternBuilder->setSegments(gfx::Triangles(),
|
||||
bucket.sharedTriangles,
|
||||
bucket.triangleSegments.data(),
|
||||
@@ -679,8 +701,8 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
|
||||
if (doOutline && outlinePatternBuilder && bucket.sharedBasicLineIndexes->elements()) {
|
||||
outlinePatternBuilder->setShader(outlineShader);
|
||||
outlinePatternBuilder->setRenderPass(renderPass);
|
||||
outlinePatternBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
|
||||
outlinePatternBuilder->setSegments(gfx::Lines(2),
|
||||
outlinePatternBuilder->setRawVertices({}, fillVertexCount, gfx::AttributeDataType::Short2);
|
||||
outlinePatternBuilder->setSegments(gfx::Lines(lineWidth),
|
||||
bucket.sharedBasicLineIndexes,
|
||||
bucket.basicLineSegments.data(),
|
||||
bucket.basicLineSegments.size());
|
||||
|
||||
@@ -450,17 +450,22 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
|
||||
}
|
||||
|
||||
// Set up tile drawable
|
||||
auto vertices = staticDataSharedVertices;
|
||||
auto* indices = &staticDataIndices;
|
||||
std::shared_ptr<HillshadeVertexVector> vertices;
|
||||
std::shared_ptr<gfx::IndexVector<gfx::Triangles>> indices;
|
||||
auto* segments = &staticDataSegments;
|
||||
|
||||
if (!bucket.vertices.empty() && !bucket.indices.empty() && !bucket.segments.empty()) {
|
||||
vertices = bucket.sharedVertices;
|
||||
indices = &bucket.indices;
|
||||
indices = bucket.sharedIndices;
|
||||
segments = &bucket.segments;
|
||||
} else {
|
||||
vertices = staticDataSharedVertices;
|
||||
indices = std::make_shared<gfx::IndexVector<gfx::Triangles>>(staticDataIndices);
|
||||
}
|
||||
|
||||
hillshadeBuilder = context.createDrawableBuilder("hillshade");
|
||||
if (!hillshadeBuilder) {
|
||||
hillshadeBuilder = context.createDrawableBuilder("hillshade");
|
||||
}
|
||||
|
||||
gfx::VertexAttributeArrayPtr hillshadeVertexAttrs;
|
||||
auto buildVertexAttributes = [&] {
|
||||
@@ -492,25 +497,14 @@ void RenderHillshadeLayer::update(gfx::ShaderRegistry& shaders,
|
||||
return false;
|
||||
}
|
||||
|
||||
drawable.setVertexAttributes(buildVertexAttributes());
|
||||
drawable.setVertices({}, vertices->elements(), gfx::AttributeDataType::Short2);
|
||||
|
||||
// Rebuild segments, since they're not shared.
|
||||
std::vector<std::unique_ptr<gfx::Drawable::DrawSegment>> drawSegments;
|
||||
drawSegments.reserve(segments->size());
|
||||
for (const auto& seg : *segments) {
|
||||
auto segCopy = SegmentBase{
|
||||
// no copy constructor
|
||||
seg.vertexOffset,
|
||||
seg.indexOffset,
|
||||
seg.vertexLength,
|
||||
seg.indexLength,
|
||||
seg.sortKey,
|
||||
};
|
||||
drawSegments.emplace_back(hillshadeBuilder->createSegment(gfx::Triangles(), std::move(segCopy)));
|
||||
}
|
||||
drawable.setIndexData(indices->vector(), std::move(drawSegments));
|
||||
drawable.updateVertexAttributes(buildVertexAttributes(),
|
||||
vertices->elements(),
|
||||
gfx::Triangles(),
|
||||
std::move(indices),
|
||||
segments->data(),
|
||||
segments->size());
|
||||
drawable.setTexture(bucket.renderTarget->getTexture(), idHillshadeImageTexture);
|
||||
|
||||
return true;
|
||||
};
|
||||
if (updateTile(renderPass, tileID, std::move(updateExisting))) {
|
||||
|
||||
@@ -377,7 +377,8 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
|
||||
|
||||
assert(!!drawable ^ !!builder);
|
||||
if (drawable) {
|
||||
drawable->setVertexAttributes(vertexAttrs);
|
||||
drawable->updateVertexAttributes(
|
||||
vertexAttrs, vertices->elements(), gfx::Triangles(), indices, segments->data(), segments->size());
|
||||
} else if (builder) {
|
||||
builder->setVertexAttributes(vertexAttrs);
|
||||
builder->setRawVertices({}, vertices->elements(), gfx::AttributeDataType::Short2);
|
||||
|
||||
@@ -100,6 +100,34 @@ void Drawable::setCullFaceMode(const gfx::CullFaceMode& mode) {
|
||||
impl->pipelineInfo.setCullMode(mode);
|
||||
}
|
||||
|
||||
void Drawable::updateVertexAttributes(gfx::VertexAttributeArrayPtr vertices,
|
||||
std::size_t vertexCount,
|
||||
gfx::DrawMode mode,
|
||||
gfx::IndexVectorBasePtr indexes,
|
||||
const SegmentBase* segments,
|
||||
std::size_t segmentCount) {
|
||||
gfx::Drawable::setVertexAttributes(std::move(vertices));
|
||||
impl->vertexCount = vertexCount;
|
||||
|
||||
std::vector<std::unique_ptr<Drawable::DrawSegment>> drawSegs;
|
||||
drawSegs.reserve(segmentCount);
|
||||
for (std::size_t i = 0; i < segmentCount; ++i) {
|
||||
const auto& seg = segments[i];
|
||||
auto segCopy = SegmentBase{
|
||||
// no copy constructor
|
||||
seg.vertexOffset,
|
||||
seg.indexOffset,
|
||||
seg.vertexLength,
|
||||
seg.indexLength,
|
||||
seg.sortKey,
|
||||
};
|
||||
drawSegs.push_back(std::make_unique<Drawable::DrawSegment>(mode, std::move(segCopy)));
|
||||
}
|
||||
|
||||
impl->indexes = std::move(indexes);
|
||||
impl->segments = std::move(drawSegs);
|
||||
}
|
||||
|
||||
void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
||||
if (isCustom) {
|
||||
return;
|
||||
@@ -116,13 +144,13 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
||||
|
||||
// We need either raw index data or a buffer already created from them.
|
||||
// We can have a buffer and no indexes, but only if it's not marked dirty.
|
||||
if (!impl->indexes || (impl->indexes->empty() &&
|
||||
(!impl->indexes->getBuffer() || impl->indexes->isModifiedAfter(attributeUpdateTime)))) {
|
||||
if (!impl->indexes || (impl->indexes->empty() && (!impl->indexes->getBuffer() || !attributeUpdateTime ||
|
||||
impl->indexes->isModifiedAfter(*attributeUpdateTime)))) {
|
||||
assert(!"Missing index data");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!impl->indexes->getBuffer() || impl->indexes->isModifiedAfter(attributeUpdateTime)) {
|
||||
if (!impl->indexes->getBuffer() || !attributeUpdateTime || impl->indexes->isModifiedAfter(*attributeUpdateTime)) {
|
||||
// Create a buffer for the index data. We don't update any
|
||||
// existing buffer because it may still be in use by the previous frame.
|
||||
auto indexBufferResource{uploadPass.createIndexBufferResource(
|
||||
@@ -134,7 +162,8 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
||||
impl->indexes->setBuffer(std::move(buffer));
|
||||
}
|
||||
|
||||
const bool buildAttribs = !vertexAttributes || vertexAttributes->isModifiedAfter(attributeUpdateTime) ||
|
||||
const bool buildAttribs = !vertexAttributes || !attributeUpdateTime ||
|
||||
vertexAttributes->isModifiedAfter(*attributeUpdateTime) ||
|
||||
impl->pipelineInfo.inputAttributes.empty();
|
||||
|
||||
if (buildAttribs) {
|
||||
@@ -166,7 +195,8 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
||||
}
|
||||
|
||||
// build instance buffer
|
||||
const bool buildInstanceBuffer = (instanceAttributes && instanceAttributes->isModifiedAfter(attributeUpdateTime));
|
||||
const bool buildInstanceBuffer =
|
||||
(instanceAttributes && (!attributeUpdateTime || instanceAttributes->isModifiedAfter(*attributeUpdateTime)));
|
||||
|
||||
if (buildInstanceBuffer) {
|
||||
// Build instance attribute buffers
|
||||
|
||||
@@ -84,7 +84,8 @@ struct VertexBuffer : public gfx::VertexBufferBase {
|
||||
static const std::unique_ptr<gfx::VertexBufferResource> noBuffer;
|
||||
|
||||
const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVectorBasePtr& vec,
|
||||
const gfx::BufferUsageType usage) {
|
||||
const gfx::BufferUsageType usage,
|
||||
bool forceUpdate) {
|
||||
if (vec) {
|
||||
const auto* rawBufPtr = vec->getRawData();
|
||||
const auto rawBufSize = vec->getRawCount() * vec->getRawSize();
|
||||
@@ -95,7 +96,7 @@ const gfx::UniqueVertexBufferResource& UploadPass::getBuffer(const gfx::VertexVe
|
||||
|
||||
// If it's changed, update it
|
||||
if (rawBufSize <= resource.getSizeInBytes()) {
|
||||
if (vec->isModifiedAfter(resource.getLastUpdated())) {
|
||||
if (forceUpdate || vec->isModifiedAfter(resource.getLastUpdated())) {
|
||||
updateVertexBufferResource(resource, rawBufPtr, rawBufSize);
|
||||
resource.setLastUpdated(vec->getLastModified());
|
||||
}
|
||||
@@ -121,7 +122,7 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings(
|
||||
const gfx::VertexAttributeArray& defaults,
|
||||
const gfx::VertexAttributeArray& overrides,
|
||||
const gfx::BufferUsageType usage,
|
||||
const std::chrono::duration<double> /*lastUpdate*/,
|
||||
const std::optional<std::chrono::duration<double>> lastUpdate,
|
||||
/*out*/ std::vector<std::unique_ptr<gfx::VertexBufferResource>>&) {
|
||||
gfx::AttributeBindingArray bindings;
|
||||
|
||||
@@ -147,7 +148,7 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings(
|
||||
}
|
||||
|
||||
// If the attribute references data shared with a bucket, get the corresponding buffer.
|
||||
if (const auto& buffer = getBuffer(effectiveAttr.getSharedRawData(), usage)) {
|
||||
if (const auto& buffer = getBuffer(effectiveAttr.getSharedRawData(), usage, !lastUpdate)) {
|
||||
assert(effectiveAttr.getSharedStride() * effectiveAttr.getSharedVertexOffset() <
|
||||
effectiveAttr.getSharedRawData()->getRawSize() * effectiveAttr.getSharedRawData()->getRawCount());
|
||||
|
||||
@@ -163,7 +164,8 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings(
|
||||
assert(effectiveAttr.getStride() > 0);
|
||||
|
||||
// Otherwise, turn the data managed by the attribute into a buffer.
|
||||
if (const auto& buffer = VertexAttribute::getBuffer(effectiveAttr, *this, gfx::BufferUsageType::StaticDraw)) {
|
||||
if (const auto& buffer = VertexAttribute::getBuffer(
|
||||
effectiveAttr, *this, gfx::BufferUsageType::StaticDraw, !lastUpdate)) {
|
||||
bindings[index] = {
|
||||
/*.attribute = */ {effectiveAttr.getDataType(), /*offset=*/0},
|
||||
/*.vertexStride = */ static_cast<uint32_t>(effectiveAttr.getStride()),
|
||||
|
||||
@@ -14,11 +14,12 @@ namespace vulkan {
|
||||
|
||||
const gfx::UniqueVertexBufferResource& VertexAttribute::getBuffer(gfx::VertexAttribute& attrib_,
|
||||
UploadPass& uploadPass,
|
||||
const gfx::BufferUsageType usage) {
|
||||
const gfx::BufferUsageType usage,
|
||||
bool forceUpdate) {
|
||||
if (!attrib_.getBuffer()) {
|
||||
auto& attrib = static_cast<VertexAttribute&>(attrib_);
|
||||
if (attrib.sharedRawData) {
|
||||
return uploadPass.getBuffer(attrib.sharedRawData, usage);
|
||||
return uploadPass.getBuffer(attrib.sharedRawData, usage, forceUpdate);
|
||||
} else {
|
||||
if (!attrib.rawData.empty()) {
|
||||
auto buffer = uploadPass.createVertexBufferResource(
|
||||
|
||||
Reference in New Issue
Block a user