aboutsummaryrefslogtreecommitdiff
path: root/src/vulkan/resource.h
blob: cd3845d5eb5a0b59e7988baf51a3a4210460c6f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2018 The Amber Authors.
//
// 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.

#ifndef SRC_VULKAN_RESOURCE_H_
#define SRC_VULKAN_RESOURCE_H_

#include <memory>
#include <vector>

#include "amber/result.h"
#include "amber/vulkan_header.h"
#include "src/datum_type.h"
#include "src/value.h"

namespace amber {
namespace vulkan {

class Device;

// Contain information of filling memory
// [|offset|, |offset| + |size_in_bytes|) with |values| whose data
// type is |type|. This information is given by script.
struct BufferInput {
  void UpdateBufferWithValues(void* buffer) const;

  uint32_t offset;
  size_t size_in_bytes;
  DataType type;              // Type of |values|.
  std::vector<Value> values;  // Data whose type is |type|.
};

// Class for Vulkan resources. Its children are Vulkan Buffer, Vulkan Image,
// and a class for push constant.
class Resource {
 public:
  virtual ~Resource();

  virtual VkDeviceMemory GetHostAccessMemory() const {
    return host_accessible_memory_;
  }

  virtual Result CopyToHost(VkCommandBuffer command) = 0;

  virtual void Shutdown();

  // Fill |memory_ptr_| from |offset| of |data| to |offset| + |size_in_bytes|
  // of |data| with |values| of |data|.
  Result UpdateMemoryWithInput(const BufferInput& input);

  // Fill |memory_ptr_| from 0 to |raw_data.size()| with |raw_data|.
  void UpdateMemoryWithRawData(const std::vector<uint8_t>& raw_data);

  virtual void* HostAccessibleMemoryPtr() const { return memory_ptr_; }

  size_t GetSizeInBytes() const { return size_in_bytes_; }

 protected:
  Resource(Device* device,
           size_t size,
           const VkPhysicalDeviceMemoryProperties& properties);
  Result Initialize();
  Result CreateVkBuffer(VkBuffer* buffer, VkBufferUsageFlags usage);

  VkBuffer GetHostAccessibleBuffer() const { return host_accessible_buffer_; }

  struct AllocateResult {
    Result r;
    uint32_t memory_type_index;
  };

  AllocateResult AllocateAndBindMemoryToVkBuffer(VkBuffer buffer,
                                                 VkDeviceMemory* memory,
                                                 VkMemoryPropertyFlags flags,
                                                 bool force_flags);
  AllocateResult AllocateAndBindMemoryToVkImage(VkImage image,
                                                VkDeviceMemory* memory,
                                                VkMemoryPropertyFlags flags,
                                                bool force_flags);

  bool IsMemoryHostAccessible(uint32_t memory_type_index) {
    return (physical_memory_properties_.memoryTypes[memory_type_index]
                .propertyFlags &
            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ==
           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
  }

  bool IsMemoryHostCoherent(uint32_t memory_type_index) {
    return (physical_memory_properties_.memoryTypes[memory_type_index]
                .propertyFlags &
            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ==
           VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
  }

  Result MapMemory(VkDeviceMemory memory);
  void UnMapMemory(VkDeviceMemory memory);

  // Set |memory_ptr_| as |ptr|. This must be used for only push constant.
  // For Vulkan buffer and image i.e., Buffer and Image classes, we should
  // not call this but uses MapMemory() method.
  void SetMemoryPtr(void* ptr) { memory_ptr_ = ptr; }

  // Make all memory operations before calling this method effective i.e.,
  // prevent hazards caused by out-of-order execution.
  void MemoryBarrier(VkCommandBuffer command);

  Device* device_ = nullptr;

 private:
  uint32_t ChooseMemory(uint32_t memory_type_bits,
                        VkMemoryPropertyFlags flags,
                        bool force_flags);
  Result AllocateMemory(VkDeviceMemory* memory,
                        VkDeviceSize size,
                        uint32_t memory_type_index);

  Result BindMemoryToVkBuffer(VkBuffer buffer, VkDeviceMemory memory);
  const VkMemoryRequirements GetVkBufferMemoryRequirements(
      VkBuffer buffer) const;

  Result BindMemoryToVkImage(VkImage image, VkDeviceMemory memory);
  const VkMemoryRequirements GetVkImageMemoryRequirements(VkImage image) const;

  size_t size_in_bytes_ = 0;
  VkPhysicalDeviceMemoryProperties physical_memory_properties_;

  VkBuffer host_accessible_buffer_ = VK_NULL_HANDLE;
  VkDeviceMemory host_accessible_memory_ = VK_NULL_HANDLE;
  void* memory_ptr_ = nullptr;
};

}  // namespace vulkan
}  // namespace amber

#endif  // SRC_VULKAN_RESOURCE_H_