blob: 70ba882b37c92b12dbdd2e9ba26011c5e42128e0 [file] [log] [blame]
/* Copyright (c) 2019-2023 The Khronos Group Inc.
* Copyright (c) 2019-2023 Valve Corporation
* Copyright (c) 2019-2023 LunarG, Inc.
* Copyright (C) 2019-2023 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* John Zulauf <jzulauf@lunarg.com>
*
*/
#pragma once
#include <functional>
#include <memory>
#include <vector>
#include "containers/range_vector.h"
#include "containers/subresource_adapter.h"
#ifndef SPARSE_CONTAINER_UNIT_TEST
#include "vulkan/vulkan.h"
#include "error_message/logging.h"
// Forward declarations...
class CMD_BUFFER_STATE;
class IMAGE_STATE;
class IMAGE_VIEW_STATE;
#endif
namespace image_layout_map {
const static VkImageLayout kInvalidLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
// Common types for this namespace
using IndexType = subresource_adapter::IndexType;
using IndexRange = sparse_container::range<IndexType>;
using Encoder = subresource_adapter::RangeEncoder;
using RangeGenerator = subresource_adapter::RangeGenerator;
struct InitialLayoutState {
VkImageView image_view; // For relaxed matching rule evaluation, else VK_NULL_HANDLE
VkImageAspectFlags aspect_mask; // For relaxed matching rules... else 0
LoggingLabel label;
InitialLayoutState(const CMD_BUFFER_STATE& cb_state_, const IMAGE_VIEW_STATE* view_state_);
InitialLayoutState() : image_view(VK_NULL_HANDLE), aspect_mask(0), label() {}
};
class ImageSubresourceLayoutMap {
public:
typedef std::function<bool(const VkImageSubresource&, VkImageLayout, VkImageLayout)> Callback;
struct SubresourceLayout {
VkImageSubresource subresource;
VkImageLayout current_layout;
VkImageLayout initial_layout;
bool operator==(const SubresourceLayout& rhs) const;
bool operator!=(const SubresourceLayout& rhs) const { return !(*this == rhs); }
SubresourceLayout(const VkImageSubresource& subresource_, VkImageLayout current_layout_, VkImageLayout initial_layout_)
: subresource(subresource_), current_layout(current_layout_), initial_layout(initial_layout_) {}
SubresourceLayout() = default;
};
struct LayoutEntry {
VkImageLayout initial_layout;
VkImageLayout current_layout;
InitialLayoutState* state;
LayoutEntry(VkImageLayout initial_ = kInvalidLayout, VkImageLayout current_ = kInvalidLayout,
InitialLayoutState* s = nullptr)
: initial_layout(initial_), current_layout(current_), state(s) {}
bool operator!=(const LayoutEntry& rhs) const {
return initial_layout != rhs.initial_layout || current_layout != rhs.current_layout || state != rhs.state;
}
bool CurrentWillChange(VkImageLayout new_layout) const {
return new_layout != kInvalidLayout && current_layout != new_layout;
}
bool Update(const LayoutEntry& src) {
bool updated_current = false;
// current_layout can be updated repeatedly.
if (CurrentWillChange(src.current_layout)) {
current_layout = src.current_layout;
updated_current = true;
}
// initial_layout and state cannot be updated once they have a valid value.
if (initial_layout == kInvalidLayout) {
initial_layout = src.initial_layout;
}
if (state == nullptr) {
state = src.state;
}
return updated_current;
}
// updater for splice()
struct Updater {
bool update(LayoutEntry& dst, const LayoutEntry& src) const { return dst.Update(src); }
std::optional<LayoutEntry> insert(const LayoutEntry& src) const {
return std::optional<LayoutEntry>(vvl::in_place, src);
}
};
};
using InitialLayoutStates = small_vector<InitialLayoutState, 2, uint32_t>;
using LayoutMap = subresource_adapter::BothRangeMap<LayoutEntry, 16>;
using RangeType = LayoutMap::key_type;
bool SetSubresourceRangeLayout(const CMD_BUFFER_STATE& cb_state, const VkImageSubresourceRange& range, VkImageLayout layout,
VkImageLayout expected_layout = kInvalidLayout);
void SetSubresourceRangeInitialLayout(const CMD_BUFFER_STATE& cb_state, const VkImageSubresourceRange& range,
VkImageLayout layout);
void SetSubresourceRangeInitialLayout(const CMD_BUFFER_STATE& cb_state, VkImageLayout layout,
const IMAGE_VIEW_STATE& view_state);
bool UpdateFrom(const ImageSubresourceLayoutMap& from);
uintptr_t CompatibilityKey() const;
const LayoutMap& GetLayoutMap() const { return layouts_; }
ImageSubresourceLayoutMap(const IMAGE_STATE& image_state);
~ImageSubresourceLayoutMap() {}
const IMAGE_STATE* GetImageView() const { return &image_state_; };
// This looks a bit ponderous but kAspectCount is a compile time constant
VkImageSubresource Decode(IndexType index) const {
const auto subres = encoder_.Decode(index);
return encoder_.MakeVkSubresource(subres);
}
RangeGenerator RangeGen(const VkImageSubresourceRange& subres_range) const {
if (encoder_.InRange(subres_range)) {
return (RangeGenerator(encoder_, subres_range));
}
// Return empty range generator
return RangeGenerator();
}
bool AnyInRange(const VkImageSubresourceRange& normalized_range,
std::function<bool(const RangeType& range, const LayoutEntry& state)>&& func) const {
return AnyInRange(RangeGen(normalized_range), std::move(func));
}
bool AnyInRange(const RangeGenerator& gen, std::function<bool(const RangeType& range, const LayoutEntry& state)>&& func) const {
return AnyInRange(RangeGenerator(gen), std::move(func));
}
bool AnyInRange(RangeGenerator&& gen, std::function<bool(const RangeType& range, const LayoutEntry& state)>&& func) const {
for (; gen->non_empty(); ++gen) {
for (auto pos = layouts_.lower_bound(*gen); (pos != layouts_.end()) && (gen->intersects(pos->first)); ++pos) {
if (func(pos->first, pos->second)) {
return true;
}
}
}
return false;
}
protected:
bool InRange(const VkImageSubresource& subres) const { return encoder_.InRange(subres); }
bool InRange(const VkImageSubresourceRange& range) const { return encoder_.InRange(range); }
private:
const IMAGE_STATE& image_state_;
const Encoder& encoder_;
LayoutMap layouts_;
InitialLayoutStates initial_layout_states_;
};
} // namespace image_layout_map