载入中...
搜索中...
未找到
Canvas.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4#include "image/ImageData.h"
5#include "zeroerr/assert.h"
6
7#include <array>
8#include <cstring>
9
10namespace eve::graphics::vulkan {
11
13 : owner(owner), width(width), height(height), hdr(hdr) {
14 ASSERT(owner != nullptr);
15 ASSERT_GT(width, 0);
16 ASSERT_GT(height, 0);
17 if (!owner) throw Exception("OffscreenCanvas: null owner");
18 if (width <= 0 || height <= 0) throw Exception("OffscreenCanvas: invalid size");
19
20 auto &device = owner->getDevice();
21 const vk::Format format =
22 hdr ? vk::Format::eR16G16B16A16Sfloat : vk::Format::eR8G8B8A8Unorm;
23 color = device.createColorTarget(uint32_t(width), uint32_t(height), format);
24
25 fb = owner->getOffscreenRenderPass(hdr).createFramebuffer(
26 device, uint32_t(width), uint32_t(height), {color.asAttachment()});
27
28 vkb::SamplerBuilder sb;
29 sampleGpu.sampler = sb.magFilter(vk::Filter::eNearest)
30 .minFilter(vk::Filter::eNearest)
31 .addressModeU(vk::SamplerAddressMode::eClampToEdge)
32 .addressModeV(vk::SamplerAddressMode::eClampToEdge)
33 .build(device);
34
35 auto sets = vkb::DescriptorSetBuilder()
36 .layout(owner->getTexSetLayout())
37 .build(device.instance, owner->getDescriptorPool());
38 sampleGpu.width = width;
39 sampleGpu.height = height;
40 sampleGpu.viewOverride = color.imageView();
41
42 vkb::UnboundSet unbound{sets[0]};
43 vkb::DescriptorSetUpdater updater;
44 updater.beginDescriptorSet(unbound)
45 .beginImages(0, 0, vk::DescriptorType::eCombinedImageSampler)
46 .image(vkb::SampledImage::forLaterSample(sampleGpu.sampler, color.imageView()))
47 .beginImages(1, 0, vk::DescriptorType::eCombinedImageSampler)
48 .image(vkb::SampledImage::forLaterSample(sampleGpu.sampler, color.imageView()))
49 .update(device.instance);
50 sampleGpu.descriptorSet = std::move(unbound).publish();
51
52 sampleTexture.width = width;
53 sampleTexture.height = height;
54 sampleTexture.pixelWidth = width;
55 sampleTexture.pixelHeight = height;
56 sampleTexture.gpuHandle = &sampleGpu;
57}
58
60 if (!owner) return;
61 auto &device = owner->getDevice();
62 device->waitIdle();
63 if (fb) {
64 device->destroyFramebuffer(fb);
65 fb = nullptr;
66 }
67 if (fb3D) {
68 device->destroyFramebuffer(fb3D);
69 fb3D = nullptr;
70 }
71 if (sampleGpu.sampler) {
72 device->destroySampler(sampleGpu.sampler);
73 sampleGpu.sampler = nullptr;
74 }
75 sampleTexture.gpuHandle = nullptr;
76}
77
79 bool v = hasPendingClear;
80 hasPendingClear = false;
81 return v;
82}
83
85 if (fb3D) return;
86 auto &device = owner->getDevice();
87 depth = device.createDepthTarget(uint32_t(width), uint32_t(height), owner->getDepthFormat(),
88 true);
89 fb3D = owner->getOffscreen3DRenderPass(hdr).createFramebuffer(
90 device, uint32_t(width), uint32_t(height), {color.asAttachment(), depth.asAttachment()});
91}
92
93void OffscreenCanvas::clear(std::optional<Color> colorOpt, std::optional<int>, std::optional<double>) {
94 clearColor = colorOpt.value_or(Color(0.f, 0.f, 0.f, 1.f));
95 hasPendingClear = true;
96}
97
98void OffscreenCanvas::readAllPixels(std::vector<uint8_t> &outRgba) {
99 if (hdr) throw Exception("HDR Canvas pixel readback requires an explicit tone-map pass");
100 auto &device = owner->getDevice();
101 device->waitIdle();
102
103 const vk::DeviceSize byteSize = vk::DeviceSize(width) * vk::DeviceSize(height) * 4;
104 vkb::GenericBuffer staging(device, vk::BufferUsageFlagBits::eTransferDst, byteSize,
105 vk::MemoryPropertyFlagBits::eHostVisible |
106 vk::MemoryPropertyFlagBits::eHostCoherent);
107
108 vkb::executeImmediately(device.instance, owner->getUploadPool(),
109 device.getQueue(vkb::QueueType::graphics), [&](vk::CommandBuffer cb) {
110 color.setLayout(cb, vk::ImageLayout::eTransferSrcOptimal);
111 vk::BufferImageCopy region{};
112 region.imageSubresource = {vk::ImageAspectFlagBits::eColor, 0, 0, 1};
113 region.imageExtent = vk::Extent3D{uint32_t(width), uint32_t(height), 1};
114 cb.copyImageToBuffer(color.image(), vk::ImageLayout::eTransferSrcOptimal,
115 staging.buffer, region);
116 color.setLayout(cb, vk::ImageLayout::eShaderReadOnlyOptimal);
117 });
118
119 outRgba.resize(size_t(byteSize));
120 void *mapped = staging.map();
121 // Vulkan FB row 0 is NDC -Y (top). Batcher maps logical y=0 → NDC -1, so
122 // logical top-left matches FB top-left — copy as-is into Y-down buffer.
123 std::memcpy(outRgba.data(), mapped, size_t(byteSize));
124 staging.unmap();
125 staging.release();
126}
127
128void OffscreenCanvas::readAllHDRPixels(std::vector<uint8_t> &outRgba16f) {
129 if (!hdr) throw Exception("Canvas is not an HDR render target");
130 auto &device = owner->getDevice();
131 device->waitIdle();
132
133 const vk::DeviceSize byteSize = vk::DeviceSize(width) * vk::DeviceSize(height) * 8;
134 vkb::GenericBuffer staging(device, vk::BufferUsageFlagBits::eTransferDst, byteSize,
135 vk::MemoryPropertyFlagBits::eHostVisible |
136 vk::MemoryPropertyFlagBits::eHostCoherent);
137
138 vkb::executeImmediately(device.instance, owner->getUploadPool(),
139 device.getQueue(vkb::QueueType::graphics), [&](vk::CommandBuffer cb) {
140 color.setLayout(cb, vk::ImageLayout::eTransferSrcOptimal);
141 vk::BufferImageCopy region{};
142 region.imageSubresource = {vk::ImageAspectFlagBits::eColor, 0, 0, 1};
143 region.imageExtent = vk::Extent3D{uint32_t(width), uint32_t(height), 1};
144 cb.copyImageToBuffer(color.image(), vk::ImageLayout::eTransferSrcOptimal,
145 staging.buffer, region);
146 color.setLayout(cb, vk::ImageLayout::eShaderReadOnlyOptimal);
147 });
148
149 outRgba16f.resize(size_t(byteSize));
150 void *mapped = staging.map();
151 std::memcpy(outRgba16f.data(), mapped, size_t(byteSize));
152 staging.unmap();
153 staging.release();
154}
155
156Color OffscreenCanvas::getPixel(int x, int y) {
157 ASSERT_GE(x, 0);
158 ASSERT_GE(y, 0);
159 ASSERT_LT(x, width);
160 ASSERT_LT(y, height);
161 if (x < 0 || y < 0 || x >= width || y >= height)
162 throw Exception("OffscreenCanvas::getPixel: out of bounds (%d,%d)", x, y);
163 std::vector<uint8_t> px;
164 readAllPixels(px);
165 size_t i = (size_t(y) * size_t(width) + size_t(x)) * 4;
166 return Color(px[i + 0] / 255.f, px[i + 1] / 255.f, px[i + 2] / 255.f, px[i + 3] / 255.f);
167}
168
169image::ImageData *OffscreenCanvas::newImageData() {
170 std::vector<uint8_t> px;
171 readAllPixels(px);
172 auto *img = new image::ImageData(width, height, "RGBA8");
173 std::memcpy(img->getData(), px.data(), px.size());
174 return img;
175}
176
177image::ImageData *OffscreenCanvas::newHDRImageData() {
178 if (!hdr) return nullptr;
179 std::vector<uint8_t> px;
180 readAllHDRPixels(px);
181 auto *img = new image::ImageData(width, height, "RGBA16F");
182 std::memcpy(img->getData(), px.data(), px.size());
183 return img;
184}
185
186} // namespace eve::graphics::vulkan
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
vkb::Device & device
float v
std::vector< Colorf > px
std::uint32_t height
std::uint32_t width
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
EVENGINE_API_BACKENDS public API.
Definition Graphics.h:342
vk::CommandPool getUploadPool() const
Returns the upload pool.
Definition Graphics.h:1016
const vkb::BuiltRenderPass & getOffscreenRenderPass(bool hdr=false) const
Returns the offscreen render pass.
Definition Graphics.h:1033
vk::DescriptorSetLayout getTexSetLayout() const
Returns the tex set layout.
Definition Graphics.h:1029
const vkb::BuiltRenderPass & getOffscreen3DRenderPass(bool hdr=false)
Returns the offscreen 3 d render pass.
Definition Graphics.h:1037
vkb::Device & getDevice()
Returns the device.
Definition Graphics.h:1014
vk::Format getDepthFormat() const
Returns the depth format.
Definition Graphics.h:1041
vk::DescriptorPool getDescriptorPool() const
Returns the descriptor pool.
Definition Graphics.h:1031
~OffscreenCanvas() override
Releases OffscreenCanvas resources.
Definition Canvas.cpp:59
void clear(std::optional< Color > color, std::optional< int > stencil, std::optional< double > depth) override
Clears .
Definition Canvas.cpp:93
OffscreenCanvas(Graphics *owner, int width, int height, bool hdr=false)
Constructs a OffscreenCanvas.
Definition Canvas.cpp:12
bool takePendingClear()
Take pending clear.
Definition Canvas.cpp:78
void ensure3D()
Ensure a D32 depth attachment + 3D (color+depth) framebuffer exist.
Definition Canvas.cpp:84
Represents raw pixel data.
Definition ImageData.h:38
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13
glm::vec4 color