在上一部分中,我们创建了一个绘制的表面。现在,我们将准备绘制的内容。但在此之前,我们应该做一些准备。我们需要向量,矩阵,缓冲区等。可以将glm
库用于我们的目的但是因为我们想要检查Kotlin Native性能本身,我将自己实现类似于一个小数学库的东西。首先,我们将创建一个带有加,减,乘,点乘积等操作的基矢量类。此外,我们需要一个伴随对象将我们的基矢量转换为具有正确尺寸的矢量。为了便于使用Vulkan
API,我们将坐标定义为字节数组。
open class Vec(vararg coordinates: Float) {
protected var buffer: FloatArray = FloatArray(coordinates.size).apply {
coordinates.copyInto(this)
}
val len by lazy {
sqrtf(this dot this)
}
val size by lazy {
coordinates.size
}
fun normalize() = len.let {
if (it != 0f)
for (i in 0 until buffer.size)
buffer[i] /= it
}
open fun normalized() = len.run {
val copyed = buffer.copyOf()
if (this != 0f)
for (i in 0 until copyed.size)
copyed[i] /= this
when (buffer.size) {
2 -> Vec.fromBuffer(*copyed) as Vec2
3 -> Vec.fromBuffer(*copyed) as Vec3
4 -> Vec.fromBuffer(*copyed) as Vec4
else -> throw IllegalArgumentException("not supported vector size")
}
}
infix fun dot(vec: Vec): Float = buffer.foldIndexed(0f) { index, sum, element ->
sum + element * vec.buffer[index]
}
open operator fun plus(scalar: Float): Vec = Vec.fromBuffer(*buffer.map {
it + scalar
}.toFloatArray())
....
companion object {
fun fromBuffer(vararg buffer: Float): Vec {
when (buffer.size) {
2 -> return Vec2(buffer[0], buffer[1])
3 -> return Vec3(buffer[0], buffer[1], buffer[2])
4 -> return Vec4(buffer[0], buffer[1], buffer[2], buffer[3])
else -> throw IllegalArgumentException("not supported vector size")
}
}
}
...
}
作为一个例子,我将展示来自基类的4维向量的继承:
class Vec4(x: Float = 0f, y: Float = 0f, z: Float = 0f, w: Float = 0f) : Vec(x, y, z, w) {
var x: Float
get() = buffer[0]
set(value) {
buffer[0] = value
}
....
var w: Float
get() = buffer[3]
set(value) {
buffer[3] = value
}
override operator fun inc(): Vec4 = super.inc() as Vec4
...
override fun normalized(): Vec4 = super.normalized() as Vec4
companion object {
val Zero = Vec4()
}
}
另外,我们需要矩阵。它们以相同的方式实现 - 首先,我们将创建一个基类,然后继承它:
基类:
open class Mat(vararg columns: Vec) {
private var _size = columns.size
protected var buffer = FloatArray(_size * _size).apply {
columns.forEachIndexed { index, vec ->
vec.toArray().forEachIndexed { idx, fl ->
this[index * columns.size + idx] = fl
}
}
}
...
open operator fun plus(v: Float): Mat {
val arr = this.toBuffer()
for (i in 0 until arr.size)
arr[i] += v
return when (size) {
2 -> Mat2.from(*arr)
3 -> Mat3.from(*arr)
4 -> Mat4.from(*arr)
else -> throw IllegalArgumentException("invalid dimensions")
}
}
...
fun toBuffer(): FloatArray = buffer.copyOfRange(0, buffer.size)
}
而且Mat4
:
class Mat4(x: Vec4 = Vec4(x = 1f), y: Vec4 = Vec4(y = 1f),
z: Vec4 = Vec4(z = 1f), w: Vec4 = Vec4(w = 1f)) : Mat(x, y, z, w) {
var X: Vec4
get() = Vec4(buffer[0], buffer[1], buffer[2], buffer[3])
set(value) {
buffer[0] = value[0]
buffer[1] = value[1]
buffer[2] = value[2]
buffer[3] = value[3]
}
...
var W: Vec4
get() = Vec4(buffer[12], buffer[13], buffer[14], buffer[15])
set(value) {
buffer[12] = value[0]
buffer[13] = value[1]
buffer[14] = value[2]
buffer[15] = value[3]
}
override operator fun inc(): Mat4 = super.inc() as Mat4
...
override operator fun minus(m: Mat): Mat4 = super.minus(m) as Mat4
companion object {
fun from(vararg a: Float): Mat4 {
assert(a.size == 16)
return Mat4(Vec4(a[0], a[1], a[2], a[3]), Vec4(a[4], a[5], a[6], a[7]),
Vec4(a[8], a[9], a[10], a[11]), Vec4(a[12], a[13], a[14], a[15]))
}
...
}
}
现在我们有了一些小数学库,但是有一些助手可以使用字节数组,因为我们将在使用Vulkan
API时使用它们。让我们为它创建一个帮助类,允许我们使用迭代器forEach
等。
@ExperimentalUnsignedTypes
internal class VulkanArray<T : CVariable>
private constructor(internal val _size: UInt) : DisposableContainer() {
internal lateinit var _array: CArrayPointer<T>
private set
companion object {
inline fun <reified K : CVariable> Make(size: UInt): VulkanArray<K> {
val array = VulkanArray<K>(size)
array._array = with(array.arena) { allocArray(size.toInt()) }
return array
}
}
}
@ExperimentalUnsignedTypes
internal inline operator fun <reified T : CVariable> VulkanArray<T>.iterator(): Iterator<T> {
return object : Iterator<T> {
var cursor = 0
override fun hasNext() = cursor < _size.toInt()
override fun next(): T = _array.get(cursor++)
}
}
@ExperimentalUnsignedTypes
internal inline fun <reified T : CVariable> VulkanArray<T>
.forEach(callback: (it: T) -> Unit) {
for (i in 0 until _size.toInt()) {
callback(_array[i])
}
}
...
现在我们准备继续。
如您所知,一次只有一个图像呈现在表面上。但我们可以创建一个队列并渲染更多图像,同时将其中一个图像呈现给屏幕。因此,交换链是队列中这种可呈现图像的数组,它允许在屏幕上显示它们。要创建交换链,我们首先会得到支持的格式,检查我们是否可以使用VK_PRESENT_MODE_IMMEDIATE_KHR
或VK_PRESENT_MODE_MAILBOX_KHR
检查我们是否可以使用复合alpha,创建交换链本身并创建带图像的缓冲区。
让我们得到支持的格式:
val formatsCount = alloc<UIntVar>()
var result: VkResult
var buffer: CArrayPointer<VkSurfaceFormatKHR>? = null
do {
result = vkGetPhysicalDeviceSurfaceFormatsKHR(pDevice.device,
surface, formatsCount.ptr, null)
if (!VK_CHECK(result)) {
throw RuntimeException("Could not get surface formats.")
}
if (formatsCount.value == 0u) break
buffer?.let {
nativeHeap.free(it)
buffer = null
}
buffer = nativeHeap.allocArray(formatsCount.value.toInt())
result =
vkGetPhysicalDeviceSurfaceFormatsKHR(
pDevice.device,
surface,
formatsCount.ptr,
buffer!!.getPointer(memScope)
)
if (!VK_CHECK(result)) {
throw RuntimeException("Could not get surface formats.")
}
} while (result == VK_INCOMPLETE)
if (formatsCount.value == 1u) {
displayFormat = buffer!![0].format
_colorSpace = buffer!![0].colorSpace
} else {
var chosenFormat: UInt? = null
for (i in 0u until formatsCount.value) {
if (buffer!![i.toInt()].format == VK_FORMAT_R8G8B8A8_UNORM) {
chosenFormat = i
break
}
}
chosenFormat?.let {
displayFormat = buffer!![it.toInt()].format
_colorSpace = buffer!![it.toInt()].colorSpace
} ?: kotlin.run {
displayFormat = buffer!![0].format
_colorSpace = buffer!![0].colorSpace
}
}
nativeHeap.free(buffer!!)
接下来,我们将定义当前模式。早些时候,在PhysicalDevice
课堂上,我们添加了surfacePresentModes
属性。如果我们不使用vsync
,我们只检查它是否包含VK_PRESENT_MODE_MAILBOX_KHR
否则VK_PRESENT_MODE_IMMEDIATE_KHR
使用它。默认情况下,它是VK_PRESENT_MODE_FIFO_KHR
。然后在表面能力中,我们应该检查最大图像计数以及它们是否包含任何复合alpha位。完成所有准备工作后,我们可以创建交换链本身和图像:
val swapchainCreateInfo: VkSwapchainCreateInfoKHR =
alloc<VkSwapchainCreateInfoKHR>().apply {
sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
...
}
...
if (!VK_CHECK(vkCreateSwapchainKHR(lDevice,
swapchainCreateInfo.ptr, null, _swapchain.ptr)))
throw RuntimeException("Failed to create swapchain")
val imagesCount: UIntVar = alloc()
if (!VK_CHECK(vkGetSwapchainImagesKHR(lDevice, _swapchain.value,
imagesCount.ptr, null)))
throw RuntimeException("Failed to initialize vulkan. No images")
_imagesBuffer = arena.allocArray(imagesCount.value.toInt())
if (!VK_CHECK(vkGetSwapchainImagesKHR(lDevice, _swapchain.value,
imagesCount.ptr, _imagesBuffer)))
throw RuntimeException("Failed to initialize vulkan. No images")
for (i in 0u until imagesCount.value) {
val imageViewCreateInfo: VkImageViewCreateInfo =
alloc<VkImageViewCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO
...
image = _imagesBuffer[i.toInt()]!!
}
val imageView = with(arena) { alloc<VkImageViewVar>() }
if (!VK_CHECK(vkCreateImageView(lDevice,
imageViewCreateInfo.ptr, null, imageView.ptr))) {
throw RuntimeException("Failed to create image views")
}
imageBuffers.add(Pair(_imagesBuffer[i.toInt()]!!, imageView))
}
...
该RenderPass
实施是很容易做到。这是使用结构和结构的标准方式。所以我留给读者检查源代码。
统一缓冲区是在视频卡的存储器中分配的只读存储区,可由着色器程序使用。所以我们应该在主机内存中准备这些区域,然后将它们传递给显卡内存。对此,是的,再一些准备步骤。首先,让我们创建一个Vertex
类:
@ExperimentalUnsignedTypes
class Vertex(position: Vec3, color: Vec3) {
var buffer: FloatArray = FloatArray(6) { 0f }
private set
var position: Vec3 ...
var color: Vec3 ...
...
companion object {
// Single vertex input binding at binding point 0
fun bindingDescription(scope: MemScope) =
scope.alloc<VkVertexInputBindingDescription>().apply {
binding = 0u
stride = Vertex.SIZE.toUInt()
inputRate = VK_VERTEX_INPUT_RATE_VERTEX
}
fun inputAtributes(scope: MemScope) =
scope.allocArray<VkVertexInputAttributeDescription>(2).apply {
// Input attribute bindings describe shader attribute locations and memory layouts
// These match the following shader layout (see triangle.vert):
// layout (location = 0) in vec3 inPos;
// layout (location = 1) in vec3 inColor;
// Attribute location 0: Position
this[0].binding = 0u
this[0].location = 0u
// Position attribute is three 32 bit signed (SFLOAT) floats (R32 G32 B32)
this[0].format = VK_FORMAT_R32G32B32_SFLOAT
this[0].offset = 0u
// Attribute location 1: Color
}
val SIZE = 6 * sizeOf<FloatVar>()
val BUFFER_SIZE = 6
}
}
现在我们可以创建一个vertex
缓冲区。我们将使用暂存缓冲区,让我们为它们创建类。StagingBuffer
本身只是几个属性,缓冲区和设备内存VkBufferVar
和VkDeviceMemoryVar
类型。并且StagingBuffers
类还包含顶点登台缓冲区和索引登台缓冲区的几个变量。顶点缓冲类的初始化将包括以下步骤:
这是实施:
@ExperimentalUnsignedTypes
internal class VertexBuffer(
private val pDevice: PhysicalDevice,
private val lDevice: LogicalDevice,
vertices: Array<Vertex>,
indices: Array<UInt>
) : DisposableContainer() {
...
init {
var voffset = 0
vertices.forEach { v ->
v.buffer.copyInto(vertexBuffer, voffset)
voffset += Vertex.BUFFER_SIZE
}
indices.forEachIndexed { index, uInt ->
indexBuffer[index] = uInt
}
memScoped {
val memoryAllocateInfo = alloc<VkMemoryAllocateInfo>().apply {
sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
}
val memReqs: VkMemoryRequirements = alloc()
// Vertex buffer
val vertexBufferInfo = alloc<VkBufferCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
size = vertexBufferSize.toULong()
usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT //copy source
}
val stagingBuffers = StagingBuffers()
if (!VK_CHECK(
vkCreateBuffer(
lDevice.device,
vertexBufferInfo.ptr,
null,
stagingBuffers.vertices.buffer.ptr
)
)
)
throw RuntimeException("Failed to create buffer")
vkGetBufferMemoryRequirements(lDevice.device,
stagingBuffers.vertices.buffer.value, memReqs.ptr)
memoryAllocateInfo.allocationSize = memReqs.size
// host visible memory and coherent
memoryAllocateInfo.memoryTypeIndex = pDevice.getMemoryType(
memReqs.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT or
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
)
val mapped = alloc<COpaquePointerVar>()
if (!VK_CHECK(
vkAllocateMemory(
lDevice.device,
memoryAllocateInfo.ptr,
null,
stagingBuffers.vertices.memory.ptr
)
)
)
throw RuntimeException("Faild allocate memory")
if (!VK_CHECK(
vkMapMemory(
lDevice.device,
stagingBuffers.vertices.memory.value,
0u,
memoryAllocateInfo.allocationSize,
0u,
mapped.ptr
)
)
)
throw RuntimeException("Faild map memory")
vertexBuffer.usePinned { buffer ->
platform.posix.memcpy(mapped.value, buffer.addressOf(0),
vertexBufferSize.toULong())
}
vkUnmapMemory(lDevice.device, stagingBuffers.vertices.memory.value)
if (!VK_CHECK(
vkBindBufferMemory(
lDevice.device,
stagingBuffers.vertices.buffer.value,
stagingBuffers.vertices.memory.value,
0u
)
)
)
throw RuntimeException("failed bind memory")
// Create a _device local buffer to accept data
vertexBufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT or
VK_BUFFER_USAGE_TRANSFER_DST_BIT
if (!VK_CHECK(vkCreateBuffer(lDevice.device, vertexBufferInfo.ptr,
null, _vertexBuffer.ptr)))
throw RuntimeException("Failed to create buffer")
vkGetBufferMemoryRequirements(lDevice.device, _vertexBuffer.value,
memReqs.ptr)
memoryAllocateInfo.allocationSize = memReqs.size
memoryAllocateInfo.memoryTypeIndex = pDevice.getMemoryType(
memReqs.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
)
if (!VK_CHECK(vkAllocateMemory(lDevice.device, memoryAllocateInfo.ptr,
null, _vertexMemory.ptr)))
throw RuntimeException("Faild allocate memory")
if (!VK_CHECK(vkBindBufferMemory(lDevice.device, _vertexBuffer.value,
_vertexMemory.value, 0u)))
throw RuntimeException("failed bind memory")
...
/* the same for index buffer */
...
// copy buffer
val copyCmd = lDevice.createCommandBuffers(VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1u, true)
val copyRegion = alloc<VkBufferCopy>()
copyRegion.size = vertexBufferSize.toULong()
vkCmdCopyBuffer(
copyCmd._array[0],
stagingBuffers.vertices.buffer.value,
_vertexBuffer.value,
1u,
copyRegion.ptr
)
...
val cc = alloc<VkCommandBufferVar>()
cc.value = copyCmd._array[0]
lDevice.flushCommandBuffer(cc, false)
vkDestroyBuffer(lDevice.device, stagingBuffers.vertices.buffer.value, null)
vkFreeMemory(lDevice.device, stagingBuffers.vertices.memory.value, null)
...
}
}
}
注意:使用它是至关重要的,usePinned
否则你会得到垃圾。它暂时固定字节数组的本机内存地址。
接下来,我们需要UboVS
上课。它只包含字节数组中的模型,视图和投影矩阵,因此将其复制到缓冲区很简单。UniformBufferVars
具有内存,缓冲区和描述符属性。
和UniformBuffers
班级:
//
@ExperimentalUnsignedTypes
internal class UniformBuffers(
private val pDevice: PhysicalDevice,
private val lDevice: LogicalDevice,
private val swapchain: SwapChain
) : DisposableContainer() {
val uniformBufferVS: UniformBufferVars = UniformBufferVars()
val uboVS: UboVS = UboVS(Mat4.ZERO, Mat4.ZERO, Mat4.ZERO)
init {
memScoped {
val memReqs = alloc<VkMemoryRequirements>()
uniformBufferVS.buffer = with(arena) { alloc() }
uniformBufferVS.memory = with(arena) { alloc() }
val bufferCreateInfo = alloc<VkBufferCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
size = UboVS.SIZE.toULong()
}
if (!VK_CHECK(vkCreateBuffer(lDevice.device, bufferCreateInfo.ptr,
null, uniformBufferVS.buffer!!.ptr)))
throw RuntimeException("failed to create buffer")
val memoryAllocateInfo = alloc<VkMemoryAllocateInfo>().apply {
sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
pNext = null
allocationSize = 0u
memoryTypeIndex = 0u
}
vkGetBufferMemoryRequirements(lDevice.device,
uniformBufferVS.buffer!!.value, memReqs.ptr)
memoryAllocateInfo.allocationSize = memReqs.size
memoryAllocateInfo.memoryTypeIndex = pDevice.getMemoryType(
memReqs.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT or
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
)
if (!VK_CHECK(vkAllocateMemory(lDevice.device,
memoryAllocateInfo.ptr, null, uniformBufferVS.memory!!.ptr)))
throw RuntimeException("failed allocate memory")
if (!VK_CHECK(
vkBindBufferMemory(
lDevice.device,
uniformBufferVS.buffer!!.value,
uniformBufferVS.memory!!.value,
0u
)
)
)
throw RuntimeException("faied bind memory")
// Store information in the uniform's descriptor
// that is used by the descriptor set
uniformBufferVS.descriptor = with(arena) { alloc() }
uniformBufferVS.descriptor!!.offset = 0u
uniformBufferVS.descriptor!!.buffer = uniformBufferVS.buffer!!.value
uniformBufferVS.descriptor!!.range = UboVS.SIZE.toULong()
}
uboVS.modelMatrix = Mat4.identity
update()
}
fun update() {
uboVS.projectionMatrix = Mat4.perspective(
radians(60f),
swapchain.width.toInt().toFloat() / swapchain.height.toInt().toFloat(),
0.1f, 256f
)
uboVS.viewMatrix = Mat4.translate(Mat4.identity, Vec3(0f, 0f, -5f))
uboVS.modelMatrix = Mat4.rotate(uboVS.modelMatrix, radians(1f), Vec3(z = 1f))
memScoped {
val data = alloc<COpaquePointerVar>()
if (!VK_CHECK(
vkMapMemory(
lDevice.device!!,
uniformBufferVS.memory!!.value,
0u,
UboVS.SIZE.toULong(),
0u,
data.ptr
)
)
)
throw RuntimeException("failed bind memory")
uboVS.buffer.usePinned { buffer ->
platform.posix.memcpy(data.value, buffer.addressOf(0),
UboVS.SIZE.toULong())
}
// Note: Since we requested a host coherent memory type for
// the uniform buffer, the write is instantly visible to the GPU
vkUnmapMemory(lDevice.device, uniformBufferVS.memory!!.value)
}
}
...
}
好的,我们快要结束了。下一次,我们将添加帧缓冲区,命令缓冲区和绘图循环。
在我们创建管道之前,我们需要管道缓存,描述符集布局,管道布局,描述符池和描述符集。它们也是以标准方式实现的renderpass,您可以在源代码中找到它们。我唯一要提的是 - 加载着色器。如果你还记得,我们编译它们并复制到assets文件夹。这里应该记住一件事 - usePinned
将它们从文件系统加载到缓冲区时。
现在,我们将在渲染管道中定义所有固定状态:
@ExperimentalUnsignedTypes
internal class Pipeline(
private val _device: LogicalDevice,
private val _pipelineLayout: PipelineLayout,
private val _renderPass: RenderPass,
private val _pipelineCache: PipelineCache,
private val _swapchain: SwapChain
) : DisposableContainer() {
...
init {
memScoped {
// Shaders
val shaderStages = allocArray<VkPipelineShaderStageCreateInfo>(2)
val cwd = ByteArray(1024)
cwd.usePinned {
getcwd(it.addressOf(0), 1024)
}
var shaderFile = "${cwd.stringFromUtf8()}/assets/shaders/triangle.vert.spv"
if(access(shaderFile, F_OK) == -1){
shaderFile = "${cwd.stringFromUtf8()}
/build/bin/mingw/mainDebugExecutable/assets/shaders/triangle.vert.spv"
if(access(shaderFile, F_OK) == -1){
shaderFile = "${cwd.stringFromUtf8()}/
build/bin/linux/mainDebugExecutable/assets/shaders/triangle.vert.spv"
}
}
// Vertex shader
shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO
shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT
shaderStages[0].module = _pipelineCache.loadShader(_device.device!!, shaderFile)
shaderStages[0].pName = "main".cstr.ptr
assert(shaderStages[0].module != null)
shaderFile = "${cwd.stringFromUtf8()}/assets/shaders/triangle.frag.spv"
if(access(shaderFile, F_OK) == -1){
shaderFile = "${cwd.stringFromUtf8()}/build/
bin/mingw/mainDebugExecutable/assets/shaders/triangle.frag.spv"
if(access(shaderFile, F_OK) == -1){
shaderFile = "${cwd.stringFromUtf8()}/build/bin/linux/
mainDebugExecutable/assets/shaders/triangle.frag.spv"
}
}
...
// Vertex input state
val pipelineVertexInputStateCreateInfo =
alloc<VkPipelineVertexInputStateCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
vertexBindingDescriptionCount = 1u
pVertexBindingDescriptions = vertexInputBindingDescription.ptr
vertexAttributeDescriptionCount = 2u
pVertexAttributeDescriptions = vertexInputAttributs
}
// Input assembly state
val pipelineInputAssemblyStateCreateInfo =
alloc<VkPipelineInputAssemblyStateCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO
topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
primitiveRestartEnable = 0u
}
// Viewport state
val viewport = alloc<VkViewport>().apply {
x = 0.0f
y = 0.0f
width = _swapchain.width.toInt().toFloat()
height = _swapchain.height.toInt().toFloat()
minDepth = 0f
maxDepth = 1f
}
val scissor = alloc<VkRect2D>().apply {
offset.x = 0
offset.y = 0
extent.width = _swapchain.width
extent.height = _swapchain.height
}
val pipelineViewportStateCreateInfo =
alloc<VkPipelineViewportStateCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO
viewportCount = 1u
scissorCount = 1u
pViewports = viewport.ptr
pScissors = scissor.ptr
}
// Rasterization state
val pipelineRasterizationStateCreateInfo =
alloc<VkPipelineRasterizationStateCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO
depthClampEnable = VK_FALSE.toUInt()
rasterizerDiscardEnable = VK_FALSE.toUInt()
polygonMode = VK_POLYGON_MODE_FILL
cullMode = VK_CULL_MODE_BACK_BIT //VK_CULL_MODE_NONE
lineWidth = 1.0f
frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE
depthBiasEnable = VK_FALSE.toUInt()
}
// Multi sampling state
val pipelineMultisampleStateCreateInfo =
alloc<VkPipelineMultisampleStateCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO
rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
pSampleMask = null
sampleShadingEnable = 0u
}
// Color blend state
val blendAttachmentState = allocArray<VkPipelineColorBlendAttachmentState>(1)
blendAttachmentState[0].apply {
colorWriteMask = VK_COLOR_COMPONENT_R_BIT or
VK_COLOR_COMPONENT_G_BIT or VK_COLOR_COMPONENT_B_BIT or
VK_COLOR_COMPONENT_A_BIT //0xfu
blendEnable = VK_FALSE.toUInt()
}
val pipelineColorBlendStateCreateInfo =
alloc<VkPipelineColorBlendStateCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO
attachmentCount = 1u
pAttachments = blendAttachmentState
logicOpEnable = 0u
logicOp = VK_LOGIC_OP_COPY
blendConstants[0] = 0.0f
blendConstants[1] = 0.0f
blendConstants[2] = 0.0f
blendConstants[3] = 0.0f
}
val pipelineCreateInfo = alloc<VkGraphicsPipelineCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO
// The layout used for this pipeline
// (can be shared among multiple pipelines using the same layout)
layout = _pipelineLayout._pipelineLayout.value
//Renderpass this pipeline is attached to
renderPass = _renderPass.renderPass.value
}
// Enable dynamic states
val dynamicStateEnables = allocArray<VkDynamicStateVar>(2)
dynamicStateEnables[0] = VK_DYNAMIC_STATE_VIEWPORT
dynamicStateEnables[1] = VK_DYNAMIC_STATE_SCISSOR
val pipelineDynamicStateCreateInfo =
alloc<VkPipelineDynamicStateCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO
pDynamicStates = dynamicStateEnables
dynamicStateCount = 2u
}
// Depth and stencil state
val pipelineDepthStencilStateCreateInfo =
alloc<VkPipelineDepthStencilStateCreateInfo>().apply {
sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
depthTestEnable = VK_TRUE.toUInt()
depthWriteEnable = VK_TRUE.toUInt()
depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL
depthBoundsTestEnable = VK_FALSE.toUInt()
back.failOp = VK_STENCIL_OP_KEEP
back.passOp = VK_STENCIL_OP_KEEP
back.compareOp = VK_COMPARE_OP_ALWAYS
stencilTestEnable = VK_FALSE.toUInt()
front.failOp = VK_STENCIL_OP_KEEP
front.passOp = VK_STENCIL_OP_KEEP
front.compareOp = VK_COMPARE_OP_ALWAYS
}
pipelineCreateInfo.stageCount = 2u
pipelineCreateInfo.pStages = shaderStages
pipelineCreateInfo.pVertexInputState = pipelineVertexInputStateCreateInfo.ptr
pipelineCreateInfo.pInputAssemblyState = pipelineInputAssemblyStateCreateInfo.ptr
pipelineCreateInfo.pRasterizationState = pipelineRasterizationStateCreateInfo.ptr
pipelineCreateInfo.pColorBlendState = pipelineColorBlendStateCreateInfo.ptr
pipelineCreateInfo.pMultisampleState = pipelineMultisampleStateCreateInfo.ptr
pipelineCreateInfo.pViewportState = pipelineViewportStateCreateInfo.ptr
pipelineCreateInfo.pDepthStencilState = pipelineDepthStencilStateCreateInfo.ptr
pipelineCreateInfo.renderPass = _renderPass.renderPass.value
pipelineCreateInfo.pDynamicState = pipelineDynamicStateCreateInfo.ptr
if (!VK_CHECK(
vkCreateGraphicsPipelines(
_device.device,
_pipelineCache.value,
1u,
pipelineCreateInfo.ptr,
null,
_pipeline.ptr
)
)
)
throw RuntimeException("failed create pipeline")
vkDestroyShaderModule(_device.device, shaderStages[0].module, null)
vkDestroyShaderModule(_device.device, shaderStages[1].module, null)
}
}
...
}
Vulkan API与Kotlin Native - Swapchain,Pipeline
转载https://www.codesocang.com/appboke/39914.html
热门源码