No more staging buffer; generic buffer doubles as staging
This commit is contained in:
22
src/Game.zig
22
src/Game.zig
@@ -21,7 +21,6 @@ const Iterator2 = math.Iterator2;
|
|||||||
const Materials = @import("engine/Materials.zig");
|
const Materials = @import("engine/Materials.zig");
|
||||||
const Player = @import("Player.zig");
|
const Player = @import("Player.zig");
|
||||||
const Skybox = @import("engine/Skybox.zig");
|
const Skybox = @import("engine/Skybox.zig");
|
||||||
const StagingBuffer = @import("engine/StagingBuffer.zig");
|
|
||||||
const Swapchain = @import("engine/Swapchain.zig");
|
const Swapchain = @import("engine/Swapchain.zig");
|
||||||
const Texture = @import("engine/Texture.zig");
|
const Texture = @import("engine/Texture.zig");
|
||||||
const Textures = @import("engine/Textures.zig");
|
const Textures = @import("engine/Textures.zig");
|
||||||
@@ -37,7 +36,8 @@ vertex_buffer: shaders.VertexBuffer,
|
|||||||
index_buffer: shaders.IndexBuffer,
|
index_buffer: shaders.IndexBuffer,
|
||||||
|
|
||||||
global_uniforms: shaders.GlobalUniformsBuffer,
|
global_uniforms: shaders.GlobalUniformsBuffer,
|
||||||
global_uniforms_staging_buffer: StagingBuffer,
|
global_uniforms_staging_buffer: shaders.GlobalUniformsBuffer,
|
||||||
|
global_uniforms_staging_ptr: *shaders.GlobalUniforms,
|
||||||
global_uniforms_transfer_semaphores: []vk.Semaphore,
|
global_uniforms_transfer_semaphores: []vk.Semaphore,
|
||||||
point_lights: shaders.PointLightBuffer,
|
point_lights: shaders.PointLightBuffer,
|
||||||
directional_lights: shaders.DirectionalLightBuffer,
|
directional_lights: shaders.DirectionalLightBuffer,
|
||||||
@@ -221,12 +221,17 @@ pub fn init() !Game {
|
|||||||
});
|
});
|
||||||
errdefer global_uniforms.deinit();
|
errdefer global_uniforms.deinit();
|
||||||
|
|
||||||
var global_uniforms_staging_buffer = try StagingBuffer.init(.{
|
var global_uniforms_staging_buffer = try shaders.GlobalUniformsBuffer.init(.{
|
||||||
.capacity = @sizeOf(shaders.GlobalUniforms),
|
.usage = .staging,
|
||||||
.target_queue = .graphics,
|
.target_queue = .graphics,
|
||||||
|
.mappable = true,
|
||||||
|
.name = "GlobalUniforms Staging",
|
||||||
});
|
});
|
||||||
errdefer global_uniforms_staging_buffer.deinit();
|
errdefer global_uniforms_staging_buffer.deinit();
|
||||||
|
|
||||||
|
const global_uniforms_staging_ptr = try global_uniforms_staging_buffer.map();
|
||||||
|
errdefer global_uniforms_staging_buffer.unmap();
|
||||||
|
|
||||||
const global_uniforms_transfer_semaphores = blk: {
|
const global_uniforms_transfer_semaphores = blk: {
|
||||||
var semaphores: std.ArrayList(vk.Semaphore) = try .initCapacity(allocator_general, swapchain.swapchain_images.len);
|
var semaphores: std.ArrayList(vk.Semaphore) = try .initCapacity(allocator_general, swapchain.swapchain_images.len);
|
||||||
errdefer semaphores.deinit(allocator_general);
|
errdefer semaphores.deinit(allocator_general);
|
||||||
@@ -744,6 +749,7 @@ pub fn init() !Game {
|
|||||||
|
|
||||||
.global_uniforms = global_uniforms,
|
.global_uniforms = global_uniforms,
|
||||||
.global_uniforms_staging_buffer = global_uniforms_staging_buffer,
|
.global_uniforms_staging_buffer = global_uniforms_staging_buffer,
|
||||||
|
.global_uniforms_staging_ptr = global_uniforms_staging_ptr,
|
||||||
.global_uniforms_transfer_semaphores = global_uniforms_transfer_semaphores,
|
.global_uniforms_transfer_semaphores = global_uniforms_transfer_semaphores,
|
||||||
.point_lights = point_lights,
|
.point_lights = point_lights,
|
||||||
.directional_lights = directional_lights,
|
.directional_lights = directional_lights,
|
||||||
@@ -776,6 +782,7 @@ pub fn deinit(self: *Game) void {
|
|||||||
self.skybox.deinit();
|
self.skybox.deinit();
|
||||||
|
|
||||||
self.global_uniforms.deinit();
|
self.global_uniforms.deinit();
|
||||||
|
self.global_uniforms_staging_buffer.unmap();
|
||||||
self.global_uniforms_staging_buffer.deinit();
|
self.global_uniforms_staging_buffer.deinit();
|
||||||
self.point_lights.deinit();
|
self.point_lights.deinit();
|
||||||
self.directional_lights.deinit();
|
self.directional_lights.deinit();
|
||||||
@@ -901,7 +908,7 @@ fn render(self: *Game) !void {
|
|||||||
|
|
||||||
const ambient_light = vm.Vector3.init(0.01, 0.01, 0.01);
|
const ambient_light = vm.Vector3.init(0.01, 0.01, 0.01);
|
||||||
|
|
||||||
const global_uniforms_data: shaders.GlobalUniforms = .{
|
self.global_uniforms_staging_ptr.* = .{
|
||||||
.matrixWStoVS = matrix_ws_to_vs,
|
.matrixWStoVS = matrix_ws_to_vs,
|
||||||
.matrixVStoCS = matrix_vs_to_cs,
|
.matrixVStoCS = matrix_vs_to_cs,
|
||||||
.matrixSSPXtoCS = matrix_sspx_to_cs,
|
.matrixSSPXtoCS = matrix_sspx_to_cs,
|
||||||
@@ -910,10 +917,7 @@ fn render(self: *Game) !void {
|
|||||||
.directionalLightCount = directional_lights_data.len,
|
.directionalLightCount = directional_lights_data.len,
|
||||||
.ambientLight = ambient_light,
|
.ambientLight = ambient_light,
|
||||||
};
|
};
|
||||||
|
try self.global_uniforms_staging_buffer.flush(0, 1);
|
||||||
const staging_memory = try self.global_uniforms_staging_buffer.map();
|
|
||||||
@memcpy(staging_memory, std.mem.asBytes(&global_uniforms_data));
|
|
||||||
self.global_uniforms_staging_buffer.unmap();
|
|
||||||
|
|
||||||
try self.deferred_command_buffers.ensureUnusedCapacity(allocator_general, 1);
|
try self.deferred_command_buffers.ensureUnusedCapacity(allocator_general, 1);
|
||||||
const global_uniforms_transfer_command_buffer = try CommandBuffer.init(.transfer);
|
const global_uniforms_transfer_command_buffer = try CommandBuffer.init(.transfer);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ const vk = @import("vulkan");
|
|||||||
|
|
||||||
const CommandBuffer = @import("CommandBuffer.zig");
|
const CommandBuffer = @import("CommandBuffer.zig");
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
const StagingBuffer = @import("StagingBuffer.zig");
|
|
||||||
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
||||||
|
|
||||||
pub const Usage = enum {
|
pub const Usage = enum {
|
||||||
@@ -14,6 +13,7 @@ pub const Usage = enum {
|
|||||||
index,
|
index,
|
||||||
vertex,
|
vertex,
|
||||||
indirect,
|
indirect,
|
||||||
|
staging,
|
||||||
|
|
||||||
pub fn asBufferUsageFlags(self: Usage) vk.BufferUsageFlags {
|
pub fn asBufferUsageFlags(self: Usage) vk.BufferUsageFlags {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
@@ -22,6 +22,7 @@ pub const Usage = enum {
|
|||||||
.index => .{ .transfer_dst_bit = true, .index_buffer_bit = true },
|
.index => .{ .transfer_dst_bit = true, .index_buffer_bit = true },
|
||||||
.vertex => .{ .transfer_dst_bit = true, .vertex_buffer_bit = true },
|
.vertex => .{ .transfer_dst_bit = true, .vertex_buffer_bit = true },
|
||||||
.indirect => .{ .transfer_dst_bit = true, .indirect_buffer_bit = true },
|
.indirect => .{ .transfer_dst_bit = true, .indirect_buffer_bit = true },
|
||||||
|
.staging => .{ .transfer_src_bit = true },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -29,6 +30,7 @@ pub const Usage = enum {
|
|||||||
pub const InitInfo = struct {
|
pub const InitInfo = struct {
|
||||||
usage: Usage,
|
usage: Usage,
|
||||||
target_queue: TargetQueue,
|
target_queue: TargetQueue,
|
||||||
|
mappable: bool = false,
|
||||||
capacity: u32 = 1,
|
capacity: u32 = 1,
|
||||||
name: ?[]const u8 = null,
|
name: ?[]const u8 = null,
|
||||||
};
|
};
|
||||||
@@ -39,6 +41,7 @@ pub fn GenericBuffer(comptime T: type) type {
|
|||||||
|
|
||||||
buffer: vk.Buffer,
|
buffer: vk.Buffer,
|
||||||
device_memory: vk.DeviceMemory,
|
device_memory: vk.DeviceMemory,
|
||||||
|
mappable: bool,
|
||||||
target_queue: TargetQueue,
|
target_queue: TargetQueue,
|
||||||
capacity: u32,
|
capacity: u32,
|
||||||
|
|
||||||
@@ -66,7 +69,10 @@ pub fn GenericBuffer(comptime T: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const memory_requirements = engine.getBufferMemoryRequirements(buffer);
|
const memory_requirements = engine.getBufferMemoryRequirements(buffer);
|
||||||
const device_memory = try engine.allocate(memory_requirements, .{ .device_local_bit = true });
|
const device_memory = try engine.allocate(memory_requirements, .{
|
||||||
|
.device_local_bit = !init_info.mappable,
|
||||||
|
.host_visible_bit = init_info.mappable,
|
||||||
|
});
|
||||||
errdefer engine.freeMemory(device_memory);
|
errdefer engine.freeMemory(device_memory);
|
||||||
if (init_info.name) |name| {
|
if (init_info.name) |name| {
|
||||||
engine.setObjectName(device_memory, "DM {s} [{s}]", .{ name, @typeName(T) });
|
engine.setObjectName(device_memory, "DM {s} [{s}]", .{ name, @typeName(T) });
|
||||||
@@ -77,6 +83,7 @@ pub fn GenericBuffer(comptime T: type) type {
|
|||||||
return .{
|
return .{
|
||||||
.buffer = buffer,
|
.buffer = buffer,
|
||||||
.device_memory = device_memory,
|
.device_memory = device_memory,
|
||||||
|
.mappable = init_info.mappable,
|
||||||
.target_queue = init_info.target_queue,
|
.target_queue = init_info.target_queue,
|
||||||
.capacity = init_info.capacity,
|
.capacity = init_info.capacity,
|
||||||
};
|
};
|
||||||
@@ -112,17 +119,30 @@ pub fn GenericBuffer(comptime T: type) type {
|
|||||||
std.debug.assert(first_index + element_count <= self.capacity);
|
std.debug.assert(first_index + element_count <= self.capacity);
|
||||||
|
|
||||||
const write_size = element_count * element_size;
|
const write_size = element_count * element_size;
|
||||||
if (write_size == 0) return;
|
if (element_count == 0) return;
|
||||||
|
|
||||||
var staging_buffer: StagingBuffer = try .init(.{
|
if (self.mappable) {
|
||||||
|
const slice = try self.mapSliceAt(first_index, element_count);
|
||||||
|
defer self.unmap();
|
||||||
|
|
||||||
|
@memcpy(slice, values);
|
||||||
|
try self.flush(first_index, element_count);
|
||||||
|
} else {
|
||||||
|
var staging_buffer: GenericBuffer(T) = try .init(.{
|
||||||
|
.usage = .staging,
|
||||||
.target_queue = self.target_queue,
|
.target_queue = self.target_queue,
|
||||||
.capacity = write_size,
|
.mappable = true,
|
||||||
|
.capacity = element_count,
|
||||||
});
|
});
|
||||||
defer staging_buffer.deinit();
|
defer staging_buffer.deinit();
|
||||||
|
|
||||||
const staging_memory = try staging_buffer.map();
|
{
|
||||||
@memcpy(staging_memory, std.mem.sliceAsBytes(values));
|
const staging_slice = try staging_buffer.mapSlice();
|
||||||
staging_buffer.unmap();
|
defer staging_buffer.unmap();
|
||||||
|
|
||||||
|
@memcpy(staging_slice, values);
|
||||||
|
try staging_buffer.flush(0, element_count);
|
||||||
|
}
|
||||||
|
|
||||||
var command_buffer: CommandBuffer = try .init(.transfer);
|
var command_buffer: CommandBuffer = try .init(.transfer);
|
||||||
defer command_buffer.deinit();
|
defer command_buffer.deinit();
|
||||||
@@ -144,5 +164,66 @@ pub fn GenericBuffer(comptime T: type) type {
|
|||||||
try command_buffer.submit(.{ .fence = fence });
|
try command_buffer.submit(.{ .fence = fence });
|
||||||
try engine.waitForFence(fence);
|
try engine.waitForFence(fence);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map(self: Self) !*T {
|
||||||
|
std.debug.assert(self.mappable);
|
||||||
|
|
||||||
|
const slice = try self.mapSliceAt(0, 1);
|
||||||
|
return &slice[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mapAt(self: Self, index: u32) !*T {
|
||||||
|
std.debug.assert(self.mappable);
|
||||||
|
|
||||||
|
const slice = try self.mapSliceAt(index, 1);
|
||||||
|
return &slice[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mapSlice(self: Self) ![]T {
|
||||||
|
std.debug.assert(self.mappable);
|
||||||
|
|
||||||
|
return self.mapSliceAt(0, self.capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mapSliceAt(self: Self, first_index: u32, count: u32) ![]T {
|
||||||
|
const engine = ctx.engine;
|
||||||
|
|
||||||
|
std.debug.assert(self.mappable);
|
||||||
|
std.debug.assert(first_index + count <= self.capacity);
|
||||||
|
|
||||||
|
const byte_offset = @as(u64, first_index) * @as(u64, element_size);
|
||||||
|
const byte_length = @as(u64, count) * @as(u64, element_size);
|
||||||
|
|
||||||
|
const mapped_memory = try engine.mapMemory(self.device_memory, byte_offset, byte_length, .{});
|
||||||
|
const slice = @as([*]T, @ptrCast(@alignCast(mapped_memory.ptr)))[0..count];
|
||||||
|
|
||||||
|
return slice;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush(self: Self, first_index: u32, count: u32) !void {
|
||||||
|
const engine = ctx.engine;
|
||||||
|
|
||||||
|
std.debug.assert(self.mappable);
|
||||||
|
std.debug.assert(first_index + count <= self.capacity);
|
||||||
|
|
||||||
|
const byte_offset = @as(u64, first_index) * @as(u64, element_size);
|
||||||
|
const byte_length = @as(u64, count) * @as(u64, element_size);
|
||||||
|
|
||||||
|
try engine.device.flushMappedMemoryRanges(&.{
|
||||||
|
.{
|
||||||
|
.memory = self.device_memory,
|
||||||
|
.offset = byte_offset,
|
||||||
|
.size = byte_length,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmap(self: Self) void {
|
||||||
|
const engine = ctx.engine;
|
||||||
|
|
||||||
|
std.debug.assert(self.mappable);
|
||||||
|
engine.unmapMemory(self.device_memory);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const vm = @import("vecmath");
|
|||||||
const CommandBuffer = @import("CommandBuffer.zig");
|
const CommandBuffer = @import("CommandBuffer.zig");
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
const GenericBuffer = @import("GenericBuffer.zig").GenericBuffer;
|
const GenericBuffer = @import("GenericBuffer.zig").GenericBuffer;
|
||||||
const StagingBuffer = @import("StagingBuffer.zig");
|
|
||||||
const Swapchain = @import("Swapchain.zig");
|
const Swapchain = @import("Swapchain.zig");
|
||||||
const Texture = @import("Texture.zig");
|
const Texture = @import("Texture.zig");
|
||||||
|
|
||||||
@@ -69,15 +68,21 @@ pub fn load(
|
|||||||
|
|
||||||
// --- LOAD IMAGE INTO STAGING BUFFER --------------------------------------
|
// --- LOAD IMAGE INTO STAGING BUFFER --------------------------------------
|
||||||
|
|
||||||
var staging_buffer = try StagingBuffer.init(.{
|
var staging_buffer = try GenericBuffer(vm.ColorHdr).init(.{
|
||||||
.capacity = @intCast(img.width * img.height * @sizeOf(vm.ColorHdr)),
|
.usage = .staging,
|
||||||
.target_queue = .compute,
|
.target_queue = .compute,
|
||||||
|
.mappable = true,
|
||||||
|
.capacity = img.width * img.height,
|
||||||
});
|
});
|
||||||
defer staging_buffer.deinit();
|
defer staging_buffer.deinit();
|
||||||
|
|
||||||
const staging_memory = try staging_buffer.map();
|
{
|
||||||
@memcpy(staging_memory, @as([*]const u8, @ptrCast(img.data)));
|
const staging_memory = try staging_buffer.mapSlice();
|
||||||
staging_buffer.unmap();
|
defer staging_buffer.unmap();
|
||||||
|
|
||||||
|
@memcpy(staging_memory, img.data);
|
||||||
|
try staging_buffer.flush(0, img.width * img.height);
|
||||||
|
}
|
||||||
|
|
||||||
// --- CREATE EQUIRECTANGULAR IMAGE ----------------------------------------
|
// --- CREATE EQUIRECTANGULAR IMAGE ----------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
const StagingBuffer = @This();
|
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
const ctx = @import("../AppContext.zig");
|
|
||||||
const vk = @import("vulkan");
|
|
||||||
|
|
||||||
const Engine = @import("Engine.zig");
|
|
||||||
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
|
||||||
|
|
||||||
buffer: vk.Buffer,
|
|
||||||
device_memory: vk.DeviceMemory,
|
|
||||||
capacity: u32,
|
|
||||||
|
|
||||||
pub const InitInfo = struct {
|
|
||||||
target_queue: TargetQueue,
|
|
||||||
capacity: u32,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn init(init_info: InitInfo) !StagingBuffer {
|
|
||||||
const engine = ctx.engine;
|
|
||||||
|
|
||||||
const target_queue_family = switch (init_info.target_queue) {
|
|
||||||
.graphics => engine.graphics_queue.allocation.family,
|
|
||||||
.compute => engine.compute_queue.allocation.family,
|
|
||||||
};
|
|
||||||
const transfer_queue_family = engine.transfer_queue.allocation.family;
|
|
||||||
|
|
||||||
const buffer = try engine.createBuffer(.{
|
|
||||||
.size = init_info.capacity,
|
|
||||||
.usage = .{
|
|
||||||
.transfer_src_bit = true,
|
|
||||||
},
|
|
||||||
.queue_family_indices = &.{ target_queue_family, transfer_queue_family },
|
|
||||||
});
|
|
||||||
errdefer engine.destroyBuffer(buffer);
|
|
||||||
|
|
||||||
const memory_requirements = engine.getBufferMemoryRequirements(buffer);
|
|
||||||
const device_memory = try engine.allocate(
|
|
||||||
memory_requirements,
|
|
||||||
.{
|
|
||||||
.host_visible_bit = true,
|
|
||||||
.host_coherent_bit = true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
errdefer engine.freeMemory(device_memory);
|
|
||||||
|
|
||||||
try engine.bindBufferMemory(buffer, device_memory, 0);
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.buffer = buffer,
|
|
||||||
.device_memory = device_memory,
|
|
||||||
.capacity = init_info.capacity,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *StagingBuffer) void {
|
|
||||||
const engine = ctx.engine;
|
|
||||||
|
|
||||||
std.log.scoped(.deinit).debug("Deinitializing {*}", .{self});
|
|
||||||
|
|
||||||
engine.freeMemory(self.device_memory);
|
|
||||||
engine.destroyBuffer(self.buffer);
|
|
||||||
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map(self: StagingBuffer) ![]u8 {
|
|
||||||
const mapped_memory = try self.mapPartial(0, self.capacity);
|
|
||||||
return mapped_memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mapPartial(self: StagingBuffer, offset: u32, len: u32) ![]u8 {
|
|
||||||
const engine = ctx.engine;
|
|
||||||
|
|
||||||
const mapped_memory = try engine.mapMemory(self.device_memory, offset, len, .{});
|
|
||||||
return mapped_memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unmap(self: StagingBuffer) void {
|
|
||||||
const engine = ctx.engine;
|
|
||||||
|
|
||||||
engine.unmapMemory(self.device_memory);
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@ const vk = @import("vulkan");
|
|||||||
const CommandBuffer = @import("CommandBuffer.zig");
|
const CommandBuffer = @import("CommandBuffer.zig");
|
||||||
const DeviceAllocation = @import("DeviceAllocation.zig");
|
const DeviceAllocation = @import("DeviceAllocation.zig");
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
const StagingBuffer = @import("StagingBuffer.zig");
|
const GenericBuffer = @import("GenericBuffer.zig").GenericBuffer;
|
||||||
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
||||||
|
|
||||||
pub const Usage = enum {
|
pub const Usage = enum {
|
||||||
@@ -207,15 +207,21 @@ pub fn writeRaw(self: Texture, data: []const u8) !void {
|
|||||||
std.debug.assert(data.len == byte_length);
|
std.debug.assert(data.len == byte_length);
|
||||||
std.debug.assert(self.usage != .depth);
|
std.debug.assert(self.usage != .depth);
|
||||||
|
|
||||||
var staging_buffer = try StagingBuffer.init(.{
|
var staging_buffer = try GenericBuffer(u8).init(.{
|
||||||
.capacity = @intCast(byte_length),
|
.usage = .staging,
|
||||||
.target_queue = self.target_queue,
|
.target_queue = self.target_queue,
|
||||||
|
.mappable = true,
|
||||||
|
.capacity = @intCast(byte_length),
|
||||||
});
|
});
|
||||||
defer staging_buffer.deinit();
|
defer staging_buffer.deinit();
|
||||||
|
|
||||||
const staging_memory = try staging_buffer.map();
|
{
|
||||||
|
const staging_memory = try staging_buffer.mapSlice();
|
||||||
|
defer staging_buffer.unmap();
|
||||||
|
|
||||||
@memcpy(staging_memory, data);
|
@memcpy(staging_memory, data);
|
||||||
staging_buffer.unmap();
|
try staging_buffer.flush(0, byte_length);
|
||||||
|
}
|
||||||
|
|
||||||
// --- TRANSITION TO TRANSFER_DST_OPTIMAL AND COPY -----------------
|
// --- TRANSITION TO TRANSFER_DST_OPTIMAL AND COPY -----------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user