[Fint] adding basic copy and blit commands
This commit is contained in:
@@ -256,21 +256,21 @@ vkAllocateDescriptorSets | ⚙️ WIP
|
||||
vkAllocateMemory | ✅ Implemented
|
||||
vkBeginCommandBuffer | ✅ Implemented
|
||||
vkBindBufferMemory | ⚙️ WIP
|
||||
vkBindImageMemory | ⚙️ WIP
|
||||
vkBindImageMemory | ✅ Implemented
|
||||
vkCmdBeginQuery | ⚙️ WIP
|
||||
vkCmdBeginRenderPass | ⚙️ WIP
|
||||
vkCmdBindDescriptorSets | ⚙️ WIP
|
||||
vkCmdBindIndexBuffer | ⚙️ WIP
|
||||
vkCmdBindPipeline | ⚙️ WIP
|
||||
vkCmdBindVertexBuffers | ⚙️ WIP
|
||||
vkCmdBlitImage | ⚙️ WIP
|
||||
vkCmdBlitImage | ✅ Implemented
|
||||
vkCmdClearAttachments | ⚙️ WIP
|
||||
vkCmdClearColorImage | ⚙️ WIP
|
||||
vkCmdClearDepthStencilImage | ⚙️ WIP
|
||||
vkCmdCopyBuffer | ✅ Implemented
|
||||
vkCmdCopyBufferToImage | ⚙️ WIP
|
||||
vkCmdCopyBufferToImage | ✅ Implemented
|
||||
vkCmdCopyImage | ⚙️ WIP
|
||||
vkCmdCopyImageToBuffer | ⚙️ WIP
|
||||
vkCmdCopyImageToBuffer | ✅ Implemented
|
||||
vkCmdCopyQueryPoolResults | ⚙️ WIP
|
||||
vkCmdDispatch | ⚙️ WIP
|
||||
vkCmdDispatchBaseKHR | ⚙️ WIP
|
||||
@@ -314,7 +314,7 @@ vkCreateEvent | ⚙️ WIP
|
||||
vkCreateFence | ⚙️ WIP
|
||||
vkCreateFramebuffer | ⚙️ WIP
|
||||
vkCreateGraphicsPipelines | ⚙️ WIP
|
||||
vkCreateImage | ⚙️ WIP
|
||||
vkCreateImage | ✅ Implemented
|
||||
vkCreateImageView | ⚙️ WIP
|
||||
vkCreateInstance | ✅ Implemented
|
||||
vkCreatePipelineCache | ⚙️ WIP
|
||||
@@ -338,7 +338,7 @@ vkDestroyDevice | ✅ Implemented
|
||||
vkDestroyEvent | ⚙️ WIP
|
||||
vkDestroyFence | ⚙️ WIP
|
||||
vkDestroyFramebuffer | ⚙️ WIP
|
||||
vkDestroyImage | ⚙️ WIP
|
||||
vkDestroyImage | ✅ Implemented
|
||||
vkDestroyImageView | ⚙️ WIP
|
||||
vkDestroyInstance | ✅ Implemented
|
||||
vkDestroyPipeline | ⚙️ WIP
|
||||
@@ -375,13 +375,13 @@ vkGetDeviceProcAddr | ⚙️ WIP
|
||||
vkGetDeviceQueue | ⚙️ WIP
|
||||
vkGetEventStatus | ⚙️ WIP
|
||||
vkGetFenceStatus | ⚙️ WIP
|
||||
vkGetImageMemoryRequirements | ⚙️ WIP
|
||||
vkGetImageMemoryRequirements | ✅ Implemented
|
||||
vkGetImageSparseMemoryRequirements | ⚙️ WIP
|
||||
vkGetImageSubresourceLayout | ⚙️ WIP
|
||||
vkGetImageSubresourceLayout | ✅ Implemented
|
||||
vkGetInstanceProcAddr | ⚙️ WIP
|
||||
vkGetPhysicalDeviceFeatures | ✅ Implemented
|
||||
vkGetPhysicalDeviceFormatProperties | ⚙️ WIP
|
||||
vkGetPhysicalDeviceImageFormatProperties | ⚙️ WIP
|
||||
vkGetPhysicalDeviceImageFormatProperties | ✅ Implemented
|
||||
vkGetPhysicalDeviceMemoryProperties | ✅ Implemented
|
||||
vkGetPhysicalDeviceProperties | ✅ Implemented
|
||||
vkGetPhysicalDeviceQueueFamilyProperties | ⚙️ WIP
|
||||
@@ -450,11 +450,11 @@ Name | Status
|
||||
-------------------------------------------------|--------
|
||||
vkAcquireNextImage2KHR | ⚙️ WIP
|
||||
vkAcquireNextImageKHR | ⚙️ WIP
|
||||
vkAllocateCommandBuffers | ⚙️ WIP
|
||||
vkAllocateCommandBuffers | ✅ Implemented
|
||||
vkAllocateDescriptorSets | ⚙️ WIP
|
||||
vkAllocateMemory | ✅ Implemented
|
||||
vkBeginCommandBuffer | ⚙️ WIP
|
||||
vkBindBufferMemory | ⚙️ WIP
|
||||
vkBeginCommandBuffer | ✅ Implemented
|
||||
vkBindBufferMemory | ✅ Implemented
|
||||
vkBindImageMemory | ⚙️ WIP
|
||||
vkCmdBeginQuery | ⚙️ WIP
|
||||
vkCmdBeginRenderPass | ⚙️ WIP
|
||||
@@ -466,7 +466,7 @@ vkCmdBlitImage | ⚙️ WIP
|
||||
vkCmdClearAttachments | ⚙️ WIP
|
||||
vkCmdClearColorImage | ⚙️ WIP
|
||||
vkCmdClearDepthStencilImage | ⚙️ WIP
|
||||
vkCmdCopyBuffer | ⚙️ WIP
|
||||
vkCmdCopyBuffer | ✅ Implemented
|
||||
vkCmdCopyBufferToImage | ⚙️ WIP
|
||||
vkCmdCopyImage | ⚙️ WIP
|
||||
vkCmdCopyImageToBuffer | ⚙️ WIP
|
||||
@@ -480,8 +480,8 @@ vkCmdDrawIndexedIndirect | ⚙️ WIP
|
||||
vkCmdDrawIndirect | ⚙️ WIP
|
||||
vkCmdEndQuery | ⚙️ WIP
|
||||
vkCmdEndRenderPass | ⚙️ WIP
|
||||
vkCmdExecuteCommands | ⚙️ WIP
|
||||
vkCmdFillBuffer | ⚙️ WIP
|
||||
vkCmdExecuteCommands | ✅ Implemented
|
||||
vkCmdFillBuffer | ✅ Implemented
|
||||
vkCmdNextSubpass | ⚙️ WIP
|
||||
vkCmdPipelineBarrier | ⚙️ WIP
|
||||
vkCmdPushConstants | ⚙️ WIP
|
||||
@@ -502,9 +502,9 @@ vkCmdSetViewport | ⚙️ WIP
|
||||
vkCmdUpdateBuffer | ⚙️ WIP
|
||||
vkCmdWaitEvents | ⚙️ WIP
|
||||
vkCmdWriteTimestamp | ⚙️ WIP
|
||||
vkCreateBuffer | ⚙️ WIP
|
||||
vkCreateBuffer | ✅ Implemented
|
||||
vkCreateBufferView | ⚙️ WIP
|
||||
vkCreateCommandPool | ⚙️ WIP
|
||||
vkCreateCommandPool | ✅ Implemented
|
||||
vkCreateComputePipelines | ⚙️ WIP
|
||||
vkCreateDescriptorPool | ⚙️ WIP
|
||||
vkCreateDescriptorSetLayout | ⚙️ WIP
|
||||
@@ -528,9 +528,9 @@ vkCreateWaylandSurfaceKHR | ⚙️ WIP
|
||||
vkCreateWin32SurfaceKHR | ⚙️ WIP
|
||||
vkCreateXcbSurfaceKHR | ⚙️ WIP
|
||||
vkCreateXlibSurfaceKHR | ⚙️ WIP
|
||||
vkDestroyBuffer | ⚙️ WIP
|
||||
vkDestroyBuffer | ✅ Implemented
|
||||
vkDestroyBufferView | ⚙️ WIP
|
||||
vkDestroyCommandPool | ⚙️ WIP
|
||||
vkDestroyCommandPool | ✅ Implemented
|
||||
vkDestroyDescriptorPool | ⚙️ WIP
|
||||
vkDestroyDescriptorSetLayout | ⚙️ WIP
|
||||
vkDestroyDevice | ✅ Implemented
|
||||
@@ -551,15 +551,15 @@ vkDestroyShaderModule | ⚙️ WIP
|
||||
vkDestroySurfaceKHR | ⚙️ WIP
|
||||
vkDestroySwapchainKHR | ⚙️ WIP
|
||||
vkDeviceWaitIdle | ⚙️ WIP
|
||||
vkEndCommandBuffer | ⚙️ WIP
|
||||
vkEnumerateDeviceExtensionProperties | ⚙️ WIP
|
||||
vkEndCommandBuffer | ✅ Implemented
|
||||
vkEnumerateDeviceExtensionProperties | ✅ Implemented
|
||||
vkEnumerateDeviceLayerProperties | ⚙️ WIP
|
||||
vkEnumerateInstanceExtensionProperties | ⚙️ WIP
|
||||
vkEnumerateInstanceLayerProperties | ⚙️ WIP
|
||||
vkEnumeratePhysicalDeviceGroupsKHR | ⚙️ WIP
|
||||
vkEnumeratePhysicalDevices | ✅ Implemented
|
||||
vkFlushMappedMemoryRanges | ⚙️ WIP
|
||||
vkFreeCommandBuffers | ⚙️ WIP
|
||||
vkFlushMappedMemoryRanges | ✅ Implemented
|
||||
vkFreeCommandBuffers | ✅ Implemented
|
||||
vkFreeDescriptorSets | ⚙️ WIP
|
||||
vkFreeMemory | ✅ Implemented
|
||||
vkGetBufferDeviceAddress | ⚙️ WIP
|
||||
@@ -570,8 +570,8 @@ vkGetDeviceGroupPeerMemoryFeaturesKHR | ⚙️ WIP
|
||||
vkGetDeviceGroupPresentCapabilitiesKHR | ⚙️ WIP
|
||||
vkGetDeviceGroupSurfacePresentModesKHR | ⚙️ WIP
|
||||
vkGetDeviceMemoryCommitment | ⚙️ WIP
|
||||
vkGetDeviceProcAddr | ⚙️ WIP
|
||||
vkGetDeviceQueue | ⚙️ WIP
|
||||
vkGetDeviceProcAddr | ✅ Implemented
|
||||
vkGetDeviceQueue | ✅ Implemented
|
||||
vkGetEventStatus | ⚙️ WIP
|
||||
vkGetFenceStatus | ⚙️ WIP
|
||||
vkGetImageMemoryRequirements | ⚙️ WIP
|
||||
@@ -597,15 +597,15 @@ vkGetPipelineCacheData | ⚙️ WIP
|
||||
vkGetQueryPoolResults | ⚙️ WIP
|
||||
vkGetRenderAreaGranularity | ⚙️ WIP
|
||||
vkGetSwapchainImagesKHR | ⚙️ WIP
|
||||
vkInvalidateMappedMemoryRanges | ⚙️ WIP
|
||||
vkInvalidateMappedMemoryRanges | ✅ Implemented
|
||||
vkMapMemory | ✅ Implemented
|
||||
vkMergePipelineCaches | ⚙️ WIP
|
||||
vkQueueBindSparse | ⚙️ WIP
|
||||
vkQueuePresentKHR | ⚙️ WIP
|
||||
vkQueueSubmit | ⚙️ WIP
|
||||
vkQueueSubmit | ✅ Implemented
|
||||
vkQueueWaitIdle | ⚙️ WIP
|
||||
vkResetCommandBuffer | ⚙️ WIP
|
||||
vkResetCommandPool | ⚙️ WIP
|
||||
vkResetCommandBuffer | ✅ Implemented
|
||||
vkResetCommandPool | ✅ Implemented
|
||||
vkResetDescriptorPool | ⚙️ WIP
|
||||
vkResetEvent | ⚙️ WIP
|
||||
vkResetFences | ⚙️ WIP
|
||||
|
||||
@@ -1,38 +1,21 @@
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
const kmd = @import("kmd.zig");
|
||||
|
||||
const VkError = base.VkError;
|
||||
const FlintDevice = @import("FlintDevice.zig");
|
||||
const FlintDeviceMemory = @import("FlintDeviceMemory.zig");
|
||||
const kmd = @import("kmd.zig");
|
||||
const FlintImage = @import("FlintImage.zig");
|
||||
|
||||
const MemoryRange = @import("MemoryRange.zig");
|
||||
|
||||
const copy = @import("copy_commands.zig");
|
||||
const blitter = @import("blitter.zig");
|
||||
|
||||
const Self = @This();
|
||||
pub const Interface = base.CommandBuffer;
|
||||
|
||||
const BufferRange = struct {
|
||||
memory: *FlintDeviceMemory,
|
||||
offset: vk.DeviceSize,
|
||||
size: vk.DeviceSize,
|
||||
|
||||
fn init(buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!BufferRange {
|
||||
const base_memory = buffer.memory orelse return VkError.InvalidDeviceMemoryDrv;
|
||||
const memory: *FlintDeviceMemory = @alignCast(@fieldParentPtr("interface", base_memory));
|
||||
|
||||
const bound, const bound_overflow = @addWithOverflow(offset, size);
|
||||
if (bound_overflow != 0 or bound > buffer.size) return VkError.ValidationFailed;
|
||||
|
||||
const memory_offset, const memory_offset_overflow = @addWithOverflow(buffer.offset, offset);
|
||||
if (memory_offset_overflow != 0) return VkError.ValidationFailed;
|
||||
|
||||
return .{
|
||||
.memory = memory,
|
||||
.offset = memory_offset,
|
||||
.size = size,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
interface: Interface,
|
||||
batch: std.ArrayList(u32),
|
||||
relocations: std.ArrayList(kmd.Relocation),
|
||||
@@ -122,39 +105,6 @@ pub fn submitGpuBatch(self: *Self) VkError!void {
|
||||
try device.kmd.submitBatch(self.interface.owner.io(), allocator, self.batch.items, self.relocations.items);
|
||||
}
|
||||
|
||||
fn emit(self: *Self, dword: u32) VkError!void {
|
||||
self.batch.append(self.interface.host_allocator.allocator(), dword) catch return VkError.OutOfHostMemory;
|
||||
}
|
||||
|
||||
fn emitRelocatedAddress(self: *Self, range: BufferRange, read: bool, write: bool) VkError!void {
|
||||
const address_offset = self.batch.items.len * @sizeOf(u32);
|
||||
try self.emit(@intCast(range.offset));
|
||||
try self.emit(0);
|
||||
self.relocations.append(self.interface.host_allocator.allocator(), .{
|
||||
.target_handle = try range.memory.allocation.handle(),
|
||||
.offset = @intCast(address_offset),
|
||||
.delta = @intCast(range.offset),
|
||||
.read = read,
|
||||
.write = write,
|
||||
}) catch return VkError.OutOfHostMemory;
|
||||
}
|
||||
|
||||
fn copyRangeFromRegion(buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!BufferRange {
|
||||
return BufferRange.init(buffer, offset, size);
|
||||
}
|
||||
|
||||
fn fillRange(buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!BufferRange {
|
||||
const resolved_size = if (size == vk.WHOLE_SIZE) blk: {
|
||||
if (offset > buffer.size) return VkError.ValidationFailed;
|
||||
break :blk std.mem.alignBackward(vk.DeviceSize, buffer.size - offset, @sizeOf(u32));
|
||||
} else blk: {
|
||||
if (size % @sizeOf(u32) != 0) return VkError.ValidationFailed;
|
||||
break :blk size;
|
||||
};
|
||||
|
||||
return BufferRange.init(buffer, offset, resolved_size);
|
||||
}
|
||||
|
||||
pub fn begin(interface: *Interface, info: *const vk.CommandBufferBeginInfo) VkError!void {
|
||||
_ = interface;
|
||||
_ = info;
|
||||
@@ -176,6 +126,23 @@ pub fn reset(interface: *Interface, flags: vk.CommandBufferResetFlags) VkError!v
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit(self: *Self, dword: u32) VkError!void {
|
||||
self.batch.append(self.interface.host_allocator.allocator(), dword) catch return VkError.OutOfHostMemory;
|
||||
}
|
||||
|
||||
pub fn emitRelocatedAddress(self: *Self, range: MemoryRange, read: bool, write: bool) VkError!void {
|
||||
const address_offset = self.batch.items.len * @sizeOf(u32);
|
||||
try self.emit(@intCast(range.offset));
|
||||
try self.emit(0);
|
||||
self.relocations.append(self.interface.host_allocator.allocator(), .{
|
||||
.target_handle = try range.memory.allocation.handle(),
|
||||
.offset = @intCast(address_offset),
|
||||
.delta = @intCast(range.offset),
|
||||
.read = read,
|
||||
.write = write,
|
||||
}) catch return VkError.OutOfHostMemory;
|
||||
}
|
||||
|
||||
pub fn beginQuery(interface: *Interface, pool: *base.QueryPool, query: u32, flags: vk.QueryControlFlags) VkError!void {
|
||||
_ = interface;
|
||||
_ = flags;
|
||||
@@ -229,13 +196,13 @@ pub fn bindVertexBuffer(interface: *Interface, index: usize, buffer: *base.Buffe
|
||||
}
|
||||
|
||||
pub fn blitImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.ImageBlit, filter: vk.Filter) VkError!void {
|
||||
_ = interface;
|
||||
_ = src;
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
_ = src_layout;
|
||||
_ = dst;
|
||||
_ = dst_layout;
|
||||
_ = regions;
|
||||
_ = filter;
|
||||
if (filter != .nearest) return VkError.FeatureNotPresent;
|
||||
|
||||
for (regions) |region|
|
||||
try blitter.blitImageRegion(self, src, dst, region);
|
||||
}
|
||||
|
||||
pub fn clearAttachment(interface: *Interface, attachment: vk.ClearAttachment, rect: vk.ClearRect) VkError!void {
|
||||
@@ -264,36 +231,17 @@ pub fn copyBuffer(interface: *Interface, src: *base.Buffer, dst: *base.Buffer, r
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
|
||||
for (regions) |region| {
|
||||
const src_range = try copyRangeFromRegion(src, region.src_offset, region.size);
|
||||
const dst_range = try copyRangeFromRegion(dst, region.dst_offset, region.size);
|
||||
|
||||
var copied: vk.DeviceSize = 0;
|
||||
while (copied < src_range.size) {
|
||||
const chunk = @min(src_range.size - copied, kmd.max_blt_span);
|
||||
const src_chunk: BufferRange = .{ .memory = src_range.memory, .offset = src_range.offset + copied, .size = chunk };
|
||||
const dst_chunk: BufferRange = .{ .memory = dst_range.memory, .offset = dst_range.offset + copied, .size = chunk };
|
||||
const width: u32 = @intCast(chunk);
|
||||
|
||||
try self.emit(kmd.xy_src_copy_blt | kmd.xy_blt_write_alpha | kmd.xy_blt_write_rgb);
|
||||
try self.emit(kmd.blt_depth_8 | kmd.rop_source_copy | width);
|
||||
try self.emit(0);
|
||||
try self.emit((1 << 16) | width);
|
||||
try self.emitRelocatedAddress(dst_chunk, false, true);
|
||||
try self.emit(0);
|
||||
try self.emit(width);
|
||||
try self.emitRelocatedAddress(src_chunk, true, false);
|
||||
|
||||
copied += chunk;
|
||||
}
|
||||
const src_range = try copy.copyRangeFromRegion(src, region.src_offset, region.size);
|
||||
const dst_range = try copy.copyRangeFromRegion(dst, region.dst_offset, region.size);
|
||||
try copy.emitLinearCopy(self, src_range, dst_range);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copyBufferToImage(interface: *Interface, src: *base.Buffer, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.BufferImageCopy) VkError!void {
|
||||
_ = interface;
|
||||
_ = src;
|
||||
_ = dst;
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
_ = dst_layout;
|
||||
_ = regions;
|
||||
for (regions) |region|
|
||||
try copy.copyBufferImage(self, src, dst, region, true);
|
||||
}
|
||||
|
||||
pub fn copyImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Image, dst_layout: vk.ImageLayout, regions: []const vk.ImageCopy) VkError!void {
|
||||
@@ -306,11 +254,10 @@ pub fn copyImage(interface: *Interface, src: *base.Image, src_layout: vk.ImageLa
|
||||
}
|
||||
|
||||
pub fn copyImageToBuffer(interface: *Interface, src: *base.Image, src_layout: vk.ImageLayout, dst: *base.Buffer, regions: []const vk.BufferImageCopy) VkError!void {
|
||||
_ = interface;
|
||||
_ = src;
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
_ = src_layout;
|
||||
_ = dst;
|
||||
_ = regions;
|
||||
for (regions) |region|
|
||||
try copy.copyBufferImage(self, dst, src, region, false);
|
||||
}
|
||||
|
||||
pub fn copyQueryPoolResults(interface: *Interface, pool: *base.QueryPool, first: u32, count: u32, dst: *base.Buffer, offset: vk.DeviceSize, stride: vk.DeviceSize, flags: vk.QueryResultFlags) VkError!void {
|
||||
@@ -409,11 +356,11 @@ pub fn executeCommands(interface: *Interface, commands: *Interface) VkError!void
|
||||
|
||||
pub fn fillBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const dst_range = try fillRange(buffer, offset, size);
|
||||
const dst_range = try copy.fillRange(buffer, offset, size);
|
||||
|
||||
var filled: vk.DeviceSize = 0;
|
||||
while (filled < dst_range.size) {
|
||||
const dst_chunk: BufferRange = .{ .memory = dst_range.memory, .offset = dst_range.offset + filled, .size = @sizeOf(u32) };
|
||||
const dst_chunk: MemoryRange = .{ .memory = dst_range.memory, .offset = dst_range.offset + filled, .size = @sizeOf(u32) };
|
||||
|
||||
try self.emit(kmd.mi_store_data_imm_dword);
|
||||
try self.emitRelocatedAddress(dst_chunk, false, true);
|
||||
|
||||
+133
-25
@@ -1,16 +1,21 @@
|
||||
//! Flint images currently use a tightly packed, linear representation.
|
||||
//! Aspects are stored consecutively. Within each aspect, every array layer
|
||||
//! contains all mip levels, and every mip level contains its depth slices and
|
||||
//! samples. Keeping this layout description here gives command encoding a
|
||||
//! single source of truth for image addresses and pitches.
|
||||
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
const lib = @import("lib.zig");
|
||||
|
||||
const FlintDeviceMemory = @import("FlintDeviceMemory.zig");
|
||||
|
||||
const VkError = base.VkError;
|
||||
|
||||
const Self = @This();
|
||||
pub const Interface = base.Image;
|
||||
|
||||
pub const F32x4 = @Vector(4, f32);
|
||||
pub const U32x4 = @Vector(4, u32);
|
||||
|
||||
interface: Interface,
|
||||
|
||||
pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.ImageCreateInfo) VkError!*Self {
|
||||
@@ -18,6 +23,9 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
var interface = try Interface.init(device, allocator, info);
|
||||
interface.allowed_memory_types = std.bit_set.IntegerBitSet(32).initEmpty();
|
||||
interface.allowed_memory_types.set(0);
|
||||
|
||||
interface.vtable = &.{
|
||||
.destroy = destroy,
|
||||
.getMemoryRequirements = getMemoryRequirements,
|
||||
@@ -28,9 +36,7 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v
|
||||
.copyToMemory = copyToMemory,
|
||||
};
|
||||
|
||||
self.* = .{
|
||||
.interface = interface,
|
||||
};
|
||||
self.* = .{ .interface = interface };
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -40,39 +46,141 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
|
||||
}
|
||||
|
||||
pub fn getMemoryRequirements(_: *Interface, requirements: *vk.MemoryRequirements) VkError!void {
|
||||
_ = requirements;
|
||||
requirements.alignment = lib.IMAGE_MEMORY_ALIGNMENT;
|
||||
requirements.size = std.mem.alignForward(vk.DeviceSize, requirements.size, lib.IMAGE_MEMORY_ALIGNMENT);
|
||||
}
|
||||
|
||||
pub fn copyToMemory(interface: *const Interface, memory: []u8, subresource: vk.ImageSubresourceLayers) VkError!void {
|
||||
_ = interface;
|
||||
_ = subresource;
|
||||
@memset(memory, 0);
|
||||
pub fn copyToMemory(interface: *const Interface, dst: []u8, subresource: vk.ImageSubresourceLayers) VkError!void {
|
||||
const self: *const Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const memory_interface = interface.memory orelse return VkError.InvalidDeviceMemoryDrv;
|
||||
const memory: *FlintDeviceMemory = @alignCast(@fieldParentPtr("interface", memory_interface));
|
||||
|
||||
try validateSingleAspect(interface.format, subresource.aspect_mask);
|
||||
if (subresource.mip_level >= interface.mip_levels or
|
||||
subresource.base_array_layer >= interface.array_layers or
|
||||
subresource.layer_count == 0)
|
||||
return VkError.ValidationFailed;
|
||||
const layer_count = if (subresource.layer_count == vk.REMAINING_ARRAY_LAYERS)
|
||||
interface.array_layers - subresource.base_array_layer
|
||||
else
|
||||
subresource.layer_count;
|
||||
if (layer_count > interface.array_layers - subresource.base_array_layer)
|
||||
return VkError.ValidationFailed;
|
||||
const level_size = self.getMultiSampledLevelSize(subresource.aspect_mask, subresource.mip_level);
|
||||
const required_size, const size_overflow = @mulWithOverflow(level_size, @as(usize, layer_count));
|
||||
if (size_overflow != 0 or dst.len < required_size) return VkError.ValidationFailed;
|
||||
|
||||
const first_offset = try self.getSubresourceOffset(
|
||||
subresource.aspect_mask,
|
||||
subresource.mip_level,
|
||||
subresource.base_array_layer,
|
||||
);
|
||||
const absolute_offset, const offset_overflow = @addWithOverflow(interface.memory_offset, first_offset);
|
||||
if (offset_overflow != 0) return VkError.ValidationFailed;
|
||||
|
||||
const device: *@import("FlintDevice.zig") = @alignCast(@fieldParentPtr("interface", interface.owner));
|
||||
const mapped = try memory.allocation.map(&device.kmd, interface.owner.io(), absolute_offset, vk.WHOLE_SIZE);
|
||||
|
||||
const layer_pitch = self.getLayerSize(subresource.aspect_mask);
|
||||
var dst_offset: usize = 0;
|
||||
var src_offset: usize = 0;
|
||||
for (0..layer_count) |_| {
|
||||
if (src_offset > mapped.len or level_size > mapped.len - src_offset)
|
||||
return VkError.InvalidDeviceMemoryDrv;
|
||||
@memcpy(dst[dst_offset..][0..level_size], mapped[src_offset..][0..level_size]);
|
||||
dst_offset += level_size;
|
||||
src_offset += layer_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getSubresourceOffset(self: *const Self, aspect_mask: vk.ImageAspectFlags, mip_level: u32, layer: u32) VkError!usize {
|
||||
if (mip_level >= self.interface.mip_levels or layer >= self.interface.array_layers)
|
||||
return VkError.ValidationFailed;
|
||||
|
||||
var offset = try self.getAspectOffset(aspect_mask);
|
||||
offset += layer * self.getLayerSize(aspect_mask);
|
||||
for (0..mip_level) |mip|
|
||||
offset += self.getMultiSampledLevelSize(aspect_mask, @intCast(mip));
|
||||
return offset;
|
||||
}
|
||||
|
||||
fn getAspectOffset(self: *const Self, aspect_mask: vk.ImageAspectFlags) VkError!usize {
|
||||
try validateSingleAspect(self.interface.format, aspect_mask);
|
||||
return switch (self.interface.format) {
|
||||
.d16_unorm_s8_uint,
|
||||
.d24_unorm_s8_uint,
|
||||
.d32_sfloat_s8_uint,
|
||||
=> if (aspect_mask.stencil_bit)
|
||||
self.interface.getTotalSizeForAspect(.{ .depth_bit = true })
|
||||
else
|
||||
0,
|
||||
else => 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getTotalSizeForAspect(interface: *const Interface, aspect_mask: vk.ImageAspectFlags) VkError!usize {
|
||||
_ = aspect_mask;
|
||||
return interface.extent.width * interface.extent.height * interface.extent.depth * base.format.texelSize(interface.format);
|
||||
const self: *const Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const valid_aspects = base.format.toAspect(interface.format);
|
||||
if (aspect_mask.toInt() == 0 or aspect_mask.subtract(valid_aspects).toInt() != 0)
|
||||
return VkError.ValidationFailed;
|
||||
|
||||
var size: usize = 0;
|
||||
if (aspect_mask.color_bit) size += self.getLayerSize(.{ .color_bit = true });
|
||||
if (aspect_mask.depth_bit) size += self.getLayerSize(.{ .depth_bit = true });
|
||||
if (aspect_mask.stencil_bit) size += self.getLayerSize(.{ .stencil_bit = true });
|
||||
return size * interface.array_layers;
|
||||
}
|
||||
|
||||
pub fn getSubresourceLayout(interface: *const Interface, subresource: vk.ImageSubresource) VkError!vk.SubresourceLayout {
|
||||
_ = subresource;
|
||||
const self: *const Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
try validateSingleAspect(interface.format, subresource.aspect_mask);
|
||||
|
||||
return .{
|
||||
.offset = 0,
|
||||
.size = try getTotalSizeForAspect(interface, base.format.toAspect(interface.format)),
|
||||
.row_pitch = getRowPitchMemSizeForMipLevel(interface, base.format.toAspect(interface.format), 0),
|
||||
.array_pitch = getSliceMemSizeForMipLevel(interface, base.format.toAspect(interface.format), 0),
|
||||
.depth_pitch = getSliceMemSizeForMipLevel(interface, base.format.toAspect(interface.format), 0),
|
||||
.offset = try self.getSubresourceOffset(subresource.aspect_mask, subresource.mip_level, subresource.array_layer),
|
||||
.size = self.getMultiSampledLevelSize(subresource.aspect_mask, subresource.mip_level),
|
||||
.row_pitch = getRowPitchMemSizeForMipLevel(interface, subresource.aspect_mask, subresource.mip_level),
|
||||
.array_pitch = self.getLayerSize(subresource.aspect_mask),
|
||||
.depth_pitch = getSliceMemSizeForMipLevel(interface, subresource.aspect_mask, subresource.mip_level),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getLayerSize(self: *const Self, aspect_mask: vk.ImageAspectFlags) usize {
|
||||
var size: usize = 0;
|
||||
for (0..self.interface.mip_levels) |mip_level|
|
||||
size += self.getMultiSampledLevelSize(aspect_mask, @intCast(mip_level));
|
||||
return size;
|
||||
}
|
||||
|
||||
pub inline fn getMultiSampledLevelSize(self: *const Self, aspect_mask: vk.ImageAspectFlags, mip_level: u32) usize {
|
||||
return self.getMipLevelSize(aspect_mask, mip_level) * self.interface.samples.toInt();
|
||||
}
|
||||
|
||||
pub inline fn getMipLevelSize(self: *const Self, aspect_mask: vk.ImageAspectFlags, mip_level: u32) usize {
|
||||
return getSliceMemSizeForMipLevel(&self.interface, aspect_mask, mip_level) * self.getMipLevelExtent(mip_level).depth;
|
||||
}
|
||||
|
||||
pub fn getMipLevelExtent(self: *const Self, mip_level: u32) vk.Extent3D {
|
||||
return .{
|
||||
.width = @max(1, self.interface.extent.width >> @intCast(mip_level)),
|
||||
.height = @max(1, self.interface.extent.height >> @intCast(mip_level)),
|
||||
.depth = @max(1, self.interface.extent.depth >> @intCast(mip_level)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getSliceMemSizeForMipLevel(interface: *const Interface, aspect_mask: vk.ImageAspectFlags, mip_level: u32) usize {
|
||||
_ = aspect_mask;
|
||||
_ = mip_level;
|
||||
return interface.extent.width * interface.extent.height * base.format.texelSize(interface.format);
|
||||
const self: *const Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const extent = self.getMipLevelExtent(mip_level);
|
||||
return base.format.sliceMemSize(base.format.fromAspect(interface.format, aspect_mask), extent.width, extent.height);
|
||||
}
|
||||
|
||||
pub fn getRowPitchMemSizeForMipLevel(interface: *const Interface, aspect_mask: vk.ImageAspectFlags, mip_level: u32) usize {
|
||||
_ = aspect_mask;
|
||||
_ = mip_level;
|
||||
return interface.extent.width * base.format.texelSize(interface.format);
|
||||
const self: *const Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const extent = self.getMipLevelExtent(mip_level);
|
||||
return base.format.pitchMemSize(base.format.fromAspect(interface.format, aspect_mask), extent.width);
|
||||
}
|
||||
|
||||
fn validateSingleAspect(format: vk.Format, aspect_mask: vk.ImageAspectFlags) VkError!void {
|
||||
const valid_aspects = base.format.toAspect(format);
|
||||
if (aspect_mask.toInt() == 0 or @popCount(aspect_mask.toInt()) != 1 or aspect_mask.subtract(valid_aspects).toInt() != 0)
|
||||
return VkError.ValidationFailed;
|
||||
}
|
||||
|
||||
@@ -377,7 +377,6 @@ pub fn getFormatProperties(interface: *Interface, format: vk.Format) VkError!vk.
|
||||
properties.optimal_tiling_features.sampled_image_bit = true;
|
||||
properties.optimal_tiling_features.transfer_dst_bit = true;
|
||||
properties.optimal_tiling_features.transfer_src_bit = true;
|
||||
properties.optimal_tiling_features.sampled_image_filter_linear_bit = true;
|
||||
},
|
||||
|
||||
// Formats which can be sampled, but don't support filtering
|
||||
@@ -417,7 +416,6 @@ pub fn getFormatProperties(interface: *Interface, format: vk.Format) VkError!vk.
|
||||
.g10x6_b10x6r10x6_2plane_420_unorm_3pack16,
|
||||
=> {
|
||||
properties.optimal_tiling_features.sampled_image_bit = true;
|
||||
properties.optimal_tiling_features.sampled_image_filter_linear_bit = true;
|
||||
properties.optimal_tiling_features.sampled_image_ycbcr_conversion_linear_filter_bit = true;
|
||||
properties.optimal_tiling_features.transfer_src_bit = true;
|
||||
properties.optimal_tiling_features.transfer_dst_bit = true;
|
||||
@@ -687,6 +685,11 @@ pub fn getFormatProperties(interface: *Interface, format: vk.Format) VkError!vk.
|
||||
properties.linear_tiling_features.transfer_dst_bit = true;
|
||||
}
|
||||
|
||||
if (properties.optimal_tiling_features.blit_src_bit or properties.optimal_tiling_features.blit_dst_bit) {
|
||||
properties.optimal_tiling_features.blit_src_bit = true;
|
||||
properties.optimal_tiling_features.blit_dst_bit = true;
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
@@ -696,20 +699,48 @@ pub fn getImageFormatProperties(
|
||||
image_type: vk.ImageType,
|
||||
tiling: vk.ImageTiling,
|
||||
usage: vk.ImageUsageFlags,
|
||||
_: vk.ImageCreateFlags,
|
||||
flags: vk.ImageCreateFlags,
|
||||
) VkError!vk.ImageFormatProperties {
|
||||
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
|
||||
if (!try self.isFormatSupported(format, image_type, tiling, usage))
|
||||
return VkError.FormatNotSupported;
|
||||
|
||||
const properties: vk.ImageFormatProperties = .{
|
||||
.max_extent = .{ .width = 0, .height = 0, .depth = 1 },
|
||||
var properties: vk.ImageFormatProperties = .{
|
||||
.max_extent = .{ .width = 1, .height = 1, .depth = 1 },
|
||||
.max_mip_levels = 1,
|
||||
.max_array_layers = 1,
|
||||
.max_array_layers = interface.props.limits.max_image_array_layers,
|
||||
.sample_counts = .{ .@"1_bit" = true },
|
||||
.max_resource_size = std.math.maxInt(u32),
|
||||
};
|
||||
|
||||
switch (image_type) {
|
||||
.@"1d" => {
|
||||
properties.max_extent.width = interface.props.limits.max_image_dimension_1d;
|
||||
properties.max_mip_levels = std.math.log2_int(u32, properties.max_extent.width) + 1;
|
||||
},
|
||||
.@"2d" => {
|
||||
const dimension = if (flags.cube_compatible_bit)
|
||||
interface.props.limits.max_image_dimension_cube
|
||||
else
|
||||
interface.props.limits.max_image_dimension_2d;
|
||||
properties.max_extent.width = dimension;
|
||||
properties.max_extent.height = dimension;
|
||||
properties.max_mip_levels = std.math.log2_int(u32, dimension) + 1;
|
||||
},
|
||||
.@"3d" => {
|
||||
const dimension = interface.props.limits.max_image_dimension_3d;
|
||||
properties.max_extent = .{ .width = dimension, .height = dimension, .depth = dimension };
|
||||
properties.max_mip_levels = std.math.log2_int(u32, dimension) + 1;
|
||||
properties.max_array_layers = 1;
|
||||
},
|
||||
else => return VkError.FormatNotSupported,
|
||||
}
|
||||
|
||||
if (tiling == .linear) {
|
||||
properties.max_mip_levels = 1;
|
||||
properties.max_array_layers = 1;
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
|
||||
const VkError = base.VkError;
|
||||
const FlintDeviceMemory = @import("FlintDeviceMemory.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
memory: *FlintDeviceMemory,
|
||||
offset: vk.DeviceSize,
|
||||
size: vk.DeviceSize,
|
||||
|
||||
pub fn fromBuffer(buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!Self {
|
||||
const base_memory = buffer.memory orelse return VkError.InvalidDeviceMemoryDrv;
|
||||
const bound, const bound_overflow = @addWithOverflow(offset, size);
|
||||
if (bound_overflow != 0 or bound > buffer.size) return VkError.ValidationFailed;
|
||||
|
||||
const memory_offset, const memory_offset_overflow = @addWithOverflow(buffer.offset, offset);
|
||||
if (memory_offset_overflow != 0) return VkError.ValidationFailed;
|
||||
|
||||
return fromMemory(base_memory, memory_offset, size);
|
||||
}
|
||||
|
||||
pub fn fromImage(image: *base.Image, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!Self {
|
||||
const base_memory = image.memory orelse return VkError.InvalidDeviceMemoryDrv;
|
||||
const memory_offset, const memory_offset_overflow = @addWithOverflow(image.memory_offset, offset);
|
||||
if (memory_offset_overflow != 0) return VkError.ValidationFailed;
|
||||
|
||||
return fromMemory(base_memory, memory_offset, size);
|
||||
}
|
||||
|
||||
pub fn fromMemory(base_memory: *base.DeviceMemory, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!Self {
|
||||
const memory: *FlintDeviceMemory = @alignCast(@fieldParentPtr("interface", base_memory));
|
||||
if (offset > base_memory.size or size > base_memory.size - offset)
|
||||
return VkError.ValidationFailed;
|
||||
|
||||
return .{
|
||||
.memory = memory,
|
||||
.offset = offset,
|
||||
.size = size,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
const kmd = @import("kmd.zig");
|
||||
|
||||
const VkError = base.VkError;
|
||||
const FlintImage = @import("FlintImage.zig");
|
||||
const FlintCommandBuffer = @import("FlintCommandBuffer.zig");
|
||||
const MemoryRange = @import("MemoryRange.zig");
|
||||
|
||||
const copy = @import("copy_commands.zig");
|
||||
|
||||
pub fn blitImageRegion(cmd: *FlintCommandBuffer, src: *base.Image, dst: *base.Image, region: vk.ImageBlit) VkError!void {
|
||||
const src_image: *FlintImage = @alignCast(@fieldParentPtr("interface", src));
|
||||
const dst_image: *FlintImage = @alignCast(@fieldParentPtr("interface", dst));
|
||||
const src_format = src.formatFromAspect(region.src_subresource.aspect_mask);
|
||||
const dst_format = dst.formatFromAspect(region.dst_subresource.aspect_mask);
|
||||
const src_texel_size = base.format.texelSize(src_format);
|
||||
const dst_texel_size = base.format.texelSize(dst_format);
|
||||
|
||||
if (src_format != dst_format or base.format.isCompressed(src_format) or base.format.isCompressed(dst_format) or src_texel_size != dst_texel_size)
|
||||
return VkError.FormatNotSupported;
|
||||
|
||||
var src_0 = region.src_offsets[0];
|
||||
var src_1 = region.src_offsets[1];
|
||||
var dst_0 = region.dst_offsets[0];
|
||||
var dst_1 = region.dst_offsets[1];
|
||||
inline for (.{ "x", "y", "z" }) |field| {
|
||||
if (@field(dst_0, field) > @field(dst_1, field)) {
|
||||
std.mem.swap(i32, &@field(src_0, field), &@field(src_1, field));
|
||||
std.mem.swap(i32, &@field(dst_0, field), &@field(dst_1, field));
|
||||
}
|
||||
}
|
||||
|
||||
if (dst_0.x < 0 or dst_0.y < 0 or dst_0.z < 0 or
|
||||
dst_0.x == dst_1.x or dst_0.y == dst_1.y or dst_0.z == dst_1.z)
|
||||
return VkError.ValidationFailed;
|
||||
|
||||
const src_extent = src_image.getMipLevelExtent(region.src_subresource.mip_level);
|
||||
const layer_count = if (region.dst_subresource.layer_count == vk.REMAINING_ARRAY_LAYERS)
|
||||
dst.array_layers - region.dst_subresource.base_array_layer
|
||||
else
|
||||
region.dst_subresource.layer_count;
|
||||
|
||||
if (layer_count == 0 or
|
||||
layer_count > src.array_layers - region.src_subresource.base_array_layer or
|
||||
layer_count > dst.array_layers - region.dst_subresource.base_array_layer)
|
||||
return VkError.ValidationFailed;
|
||||
|
||||
const copy_whole_rows = src_1.x - src_0.x == dst_1.x - dst_0.x and src_1.x > src_0.x;
|
||||
for (0..layer_count) |layer| {
|
||||
const src_layer = region.src_subresource.base_array_layer + @as(u32, @intCast(layer));
|
||||
const dst_layer = region.dst_subresource.base_array_layer + @as(u32, @intCast(layer));
|
||||
|
||||
var dst_z = dst_0.z;
|
||||
while (dst_z < dst_1.z) : (dst_z += 1) {
|
||||
const src_z = nearestBlitCoordinate(src_0.z, src_1.z, dst_0.z, dst_1.z, dst_z, src_extent.depth);
|
||||
var dst_y = dst_0.y;
|
||||
while (dst_y < dst_1.y) : (dst_y += 1) {
|
||||
const src_y = nearestBlitCoordinate(src_0.y, src_1.y, dst_0.y, dst_1.y, dst_y, src_extent.height);
|
||||
|
||||
if (copy_whole_rows) {
|
||||
const src_offset = try imageTexelOffset(src_image, region.src_subresource.aspect_mask, region.src_subresource.mip_level, src_layer, @intCast(src_0.x), src_y, src_z);
|
||||
const dst_offset = try imageTexelOffset(dst_image, region.dst_subresource.aspect_mask, region.dst_subresource.mip_level, dst_layer, @intCast(dst_0.x), @intCast(dst_y), @intCast(dst_z));
|
||||
const size: usize = @as(usize, @intCast(dst_1.x - dst_0.x)) * dst_texel_size;
|
||||
try copy.emitLinearCopy(
|
||||
cmd,
|
||||
try MemoryRange.fromImage(src, src_offset, size),
|
||||
try MemoryRange.fromImage(dst, dst_offset, size),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
var dst_x = dst_0.x;
|
||||
while (dst_x < dst_1.x) : (dst_x += 1) {
|
||||
const src_x = nearestBlitCoordinate(src_0.x, src_1.x, dst_0.x, dst_1.x, dst_x, src_extent.width);
|
||||
const src_offset = try imageTexelOffset(src_image, region.src_subresource.aspect_mask, region.src_subresource.mip_level, src_layer, src_x, src_y, src_z);
|
||||
const dst_offset = try imageTexelOffset(dst_image, region.dst_subresource.aspect_mask, region.dst_subresource.mip_level, dst_layer, @intCast(dst_x), @intCast(dst_y), @intCast(dst_z));
|
||||
try copy.emitLinearCopy(
|
||||
cmd,
|
||||
try MemoryRange.fromImage(src, src_offset, src_texel_size),
|
||||
try MemoryRange.fromImage(dst, dst_offset, dst_texel_size),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn nearestBlitCoordinate(src_0: i32, src_1: i32, dst_0: i32, dst_1: i32, dst: i32, extent: u32) usize {
|
||||
const numerator = @as(i64, 2 * (dst - dst_0) + 1) * @as(i64, src_1 - src_0);
|
||||
const denominator = @as(i64, 2 * (dst_1 - dst_0));
|
||||
const coordinate = @as(i64, src_0) + @divFloor(numerator, denominator);
|
||||
return @intCast(std.math.clamp(coordinate, 0, @as(i64, extent) - 1));
|
||||
}
|
||||
|
||||
fn imageTexelOffset(image: *const FlintImage, aspect: vk.ImageAspectFlags, mip_level: u32, layer: u32, x: usize, y: usize, z: usize) VkError!usize {
|
||||
const format = image.interface.formatFromAspect(aspect);
|
||||
return try image.getSubresourceOffset(aspect, mip_level, layer) +
|
||||
z * image.interface.getSliceMemSizeForMipLevel(aspect, mip_level) +
|
||||
y * image.interface.getRowPitchMemSizeForMipLevel(aspect, mip_level) +
|
||||
x * base.format.texelSize(format);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const base = @import("base");
|
||||
const kmd = @import("kmd.zig");
|
||||
|
||||
const VkError = base.VkError;
|
||||
const FlintImage = @import("FlintImage.zig");
|
||||
const FlintCommandBuffer = @import("FlintCommandBuffer.zig");
|
||||
const MemoryRange = @import("MemoryRange.zig");
|
||||
|
||||
pub fn emitLinearCopy(cmd: *FlintCommandBuffer, src: MemoryRange, dst: MemoryRange) VkError!void {
|
||||
if (src.size != dst.size) return VkError.ValidationFailed;
|
||||
|
||||
var copied: vk.DeviceSize = 0;
|
||||
while (copied < src.size) {
|
||||
const chunk = @min(src.size - copied, kmd.max_blt_span);
|
||||
const src_chunk: MemoryRange = .{ .memory = src.memory, .offset = src.offset + copied, .size = chunk };
|
||||
const dst_chunk: MemoryRange = .{ .memory = dst.memory, .offset = dst.offset + copied, .size = chunk };
|
||||
const width: u32 = @intCast(chunk);
|
||||
|
||||
try cmd.emit(kmd.xy_src_copy_blt | kmd.xy_blt_write_alpha | kmd.xy_blt_write_rgb);
|
||||
try cmd.emit(kmd.blt_depth_8 | kmd.rop_source_copy | width);
|
||||
try cmd.emit(0);
|
||||
try cmd.emit((1 << 16) | width);
|
||||
try cmd.emitRelocatedAddress(dst_chunk, false, true);
|
||||
try cmd.emit(0);
|
||||
try cmd.emit(width);
|
||||
try cmd.emitRelocatedAddress(src_chunk, true, false);
|
||||
|
||||
copied += chunk;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copyBufferImage(cmd: *FlintCommandBuffer, buffer: *base.Buffer, image_interface: *base.Image, region: vk.BufferImageCopy, image_is_dst: bool) VkError!void {
|
||||
if (region.image_extent.width == 0 or region.image_extent.height == 0 or region.image_extent.depth == 0)
|
||||
return;
|
||||
if (region.image_offset.x < 0 or region.image_offset.y < 0 or region.image_offset.z < 0)
|
||||
return VkError.ValidationFailed;
|
||||
|
||||
const image: *FlintImage = @alignCast(@fieldParentPtr("interface", image_interface));
|
||||
const format = image_interface.formatFromAspect(region.image_subresource.aspect_mask);
|
||||
const bytes_per_block = base.format.texelSize(format);
|
||||
const block_width = base.format.blockWidth(format);
|
||||
const block_height = base.format.blockHeight(format);
|
||||
|
||||
const buffer_width = if (region.buffer_row_length == 0) region.image_extent.width else region.buffer_row_length;
|
||||
const buffer_height = if (region.buffer_image_height == 0) region.image_extent.height else region.buffer_image_height;
|
||||
const buffer_row_pitch = base.format.pitchMemSize(format, buffer_width);
|
||||
const buffer_slice_pitch = base.format.sliceMemSize(format, buffer_width, buffer_height);
|
||||
const copy_row_size = base.format.pitchMemSize(format, region.image_extent.width);
|
||||
const copy_rows = base.format.blockCountY(format, region.image_extent.height);
|
||||
|
||||
const layer_count = if (region.image_subresource.layer_count == vk.REMAINING_ARRAY_LAYERS)
|
||||
image_interface.array_layers - region.image_subresource.base_array_layer
|
||||
else
|
||||
region.image_subresource.layer_count;
|
||||
if (layer_count == 0 or layer_count > image_interface.array_layers - region.image_subresource.base_array_layer)
|
||||
return VkError.ValidationFailed;
|
||||
|
||||
const image_row_pitch = image_interface.getRowPitchMemSizeForMipLevel(region.image_subresource.aspect_mask, region.image_subresource.mip_level);
|
||||
const image_slice_pitch = image_interface.getSliceMemSizeForMipLevel(region.image_subresource.aspect_mask, region.image_subresource.mip_level);
|
||||
const image_x_offset = @divFloor(@as(usize, @intCast(region.image_offset.x)), block_width) * bytes_per_block;
|
||||
const image_y_offset = @divFloor(@as(usize, @intCast(region.image_offset.y)), block_height);
|
||||
|
||||
for (0..layer_count) |layer| {
|
||||
const image_subresource_offset = try image.getSubresourceOffset(
|
||||
region.image_subresource.aspect_mask,
|
||||
region.image_subresource.mip_level,
|
||||
region.image_subresource.base_array_layer + @as(u32, @intCast(layer)),
|
||||
);
|
||||
|
||||
for (0..region.image_extent.depth) |z| {
|
||||
for (0..copy_rows) |row| {
|
||||
const buffer_offset = region.buffer_offset +
|
||||
(layer * region.image_extent.depth + z) * buffer_slice_pitch +
|
||||
row * buffer_row_pitch;
|
||||
const image_offset = image_subresource_offset +
|
||||
(@as(usize, @intCast(region.image_offset.z)) + z) * image_slice_pitch +
|
||||
(image_y_offset + row) * image_row_pitch +
|
||||
image_x_offset;
|
||||
|
||||
const buffer_range = try MemoryRange.fromBuffer(buffer, buffer_offset, copy_row_size);
|
||||
const image_range = try MemoryRange.fromImage(image_interface, image_offset, copy_row_size);
|
||||
if (image_is_dst)
|
||||
try emitLinearCopy(cmd, buffer_range, image_range)
|
||||
else
|
||||
try emitLinearCopy(cmd, image_range, buffer_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copyRangeFromRegion(buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!MemoryRange {
|
||||
return MemoryRange.fromBuffer(buffer, offset, size);
|
||||
}
|
||||
|
||||
pub fn fillRange(buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!MemoryRange {
|
||||
const resolved_size = if (size == vk.WHOLE_SIZE) blk: {
|
||||
if (offset > buffer.size) return VkError.ValidationFailed;
|
||||
break :blk std.mem.alignBackward(vk.DeviceSize, buffer.size - offset, @sizeOf(u32));
|
||||
} else blk: {
|
||||
if (size % @sizeOf(u32) != 0) return VkError.ValidationFailed;
|
||||
break :blk size;
|
||||
};
|
||||
|
||||
return MemoryRange.fromBuffer(buffer, offset, resolved_size);
|
||||
}
|
||||
@@ -48,6 +48,9 @@ pub const VULKAN_VERSION = vk.makeApiVersion(
|
||||
config.flint_vulkan_version.patch,
|
||||
);
|
||||
|
||||
/// GEM buffer objects are page based
|
||||
pub const IMAGE_MEMORY_ALIGNMENT = std.heap.page_size_max;
|
||||
|
||||
pub const KmdType = enum {
|
||||
Invalid,
|
||||
I915,
|
||||
|
||||
@@ -63,7 +63,7 @@ pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void {
|
||||
|
||||
pub fn bindMemory(self: *Self, memory: *DeviceMemory, offset: vk.DeviceSize) VkError!void {
|
||||
const image_size = try self.getTotalSize();
|
||||
if (offset + image_size > memory.size or !self.allowed_memory_types.isSet(memory.memory_type_index)) {
|
||||
if (offset > memory.size or image_size > memory.size - offset or !self.allowed_memory_types.isSet(memory.memory_type_index)) {
|
||||
return VkError.ValidationFailed;
|
||||
}
|
||||
self.memory = memory;
|
||||
@@ -72,7 +72,7 @@ pub fn bindMemory(self: *Self, memory: *DeviceMemory, offset: vk.DeviceSize) VkE
|
||||
|
||||
pub fn getMemoryRequirements(self: *Self, requirements: *vk.MemoryRequirements) VkError!void {
|
||||
requirements.size = try self.getTotalSize();
|
||||
requirements.memory_type_bits = 1;
|
||||
requirements.memory_type_bits = self.allowed_memory_types.mask;
|
||||
try self.vtable.getMemoryRequirements(self, requirements);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Image
|
||||
|
||||
const memory = try device.allocateMemory(allocator, &.{
|
||||
.allocation_size = requirements.size,
|
||||
.memory_type_index = requirements.memory_type_bits,
|
||||
.memory_type_index = @ctz(requirements.memory_type_bits),
|
||||
});
|
||||
errdefer memory.destroy(allocator);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user