Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
V
Vulkan render to OpenGL texture
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package registry
Model registry
Operate
Terraform modules
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Antonio Ospite
Vulkan render to OpenGL texture
Commits
a6cbaf15
Commit
a6cbaf15
authored
3 years ago
by
Antonio Ospite
Browse files
Options
Downloads
Patches
Plain Diff
Make renderheadless like a library that returns rendered images
parent
c90c7c45
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
external/Vulkan/examples/renderheadless/renderheadless.cpp
+229
-192
229 additions, 192 deletions
external/Vulkan/examples/renderheadless/renderheadless.cpp
external/Vulkan/examples/renderheadless/renderheadless.h
+16
-0
16 additions, 0 deletions
external/Vulkan/examples/renderheadless/renderheadless.h
with
245 additions
and
192 deletions
external/Vulkan/examples/renderheadless/renderheadless.cpp
+
229
−
192
View file @
a6cbaf15
...
@@ -6,6 +6,8 @@
...
@@ -6,6 +6,8 @@
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
*/
#include
"renderheadless.h"
#if defined(_WIN32)
#if defined(_WIN32)
#pragma comment(linker, "/subsystem:console")
#pragma comment(linker, "/subsystem:console")
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
#elif defined(VK_USE_PLATFORM_ANDROID_KHR)
...
@@ -93,6 +95,17 @@ public:
...
@@ -93,6 +95,17 @@ public:
VkDebugReportCallbackEXT
debugReportCallback
{};
VkDebugReportCallbackEXT
debugReportCallback
{};
static
constexpr
uint32_t
kMaxTargets
{
3
};
struct
TargetImage
{
VkImage
image
{
VK_NULL_HANDLE
};
VkDeviceMemory
mem
{
VK_NULL_HANDLE
};
VkSemaphore
renderDone
{
VK_NULL_HANDLE
};
VkSemaphore
presentDone
{
VK_NULL_HANDLE
};
};
TargetImage
targets_
[
kMaxTargets
];
uint32_t
currentTarget
=
0
;
uint32_t
getMemoryTypeIndex
(
uint32_t
typeBits
,
VkMemoryPropertyFlags
properties
)
{
uint32_t
getMemoryTypeIndex
(
uint32_t
typeBits
,
VkMemoryPropertyFlags
properties
)
{
VkPhysicalDeviceMemoryProperties
deviceMemoryProperties
;
VkPhysicalDeviceMemoryProperties
deviceMemoryProperties
;
vkGetPhysicalDeviceMemoryProperties
(
physicalDevice
,
&
deviceMemoryProperties
);
vkGetPhysicalDeviceMemoryProperties
(
physicalDevice
,
&
deviceMemoryProperties
);
...
@@ -137,11 +150,15 @@ public:
...
@@ -137,11 +150,15 @@ public:
/*
/*
Submit command buffer to a queue and wait for fence until queue operations have been finished
Submit command buffer to a queue and wait for fence until queue operations have been finished
*/
*/
void
submitWork
(
VkCommandBuffer
cmdBuffer
,
VkQueue
queue
)
void
submitWork
(
VkCommandBuffer
cmdBuffer
,
VkQueue
queue
,
VkSemaphore
wait
=
NULL
,
VkSemaphore
signal
=
NULL
)
{
{
VkSubmitInfo
submitInfo
=
vks
::
initializers
::
submitInfo
();
VkSubmitInfo
submitInfo
=
vks
::
initializers
::
submitInfo
();
submitInfo
.
commandBufferCount
=
1
;
submitInfo
.
commandBufferCount
=
1
;
submitInfo
.
pCommandBuffers
=
&
cmdBuffer
;
submitInfo
.
pCommandBuffers
=
&
cmdBuffer
;
submitInfo
.
waitSemaphoreCount
=
wait
==
NULL
?
0
:
1
;
submitInfo
.
pWaitSemaphores
=
wait
==
NULL
?
NULL
:
&
wait
;
submitInfo
.
signalSemaphoreCount
=
signal
==
NULL
?
0
:
1
;
submitInfo
.
pSignalSemaphores
=
signal
==
NULL
?
NULL
:
&
signal
;
VkFenceCreateInfo
fenceInfo
=
vks
::
initializers
::
fenceCreateInfo
();
VkFenceCreateInfo
fenceInfo
=
vks
::
initializers
::
fenceCreateInfo
();
VkFence
fence
;
VkFence
fence
;
VK_CHECK_RESULT
(
vkCreateFence
(
device
,
&
fenceInfo
,
nullptr
,
&
fence
));
VK_CHECK_RESULT
(
vkCreateFence
(
device
,
&
fenceInfo
,
nullptr
,
&
fence
));
...
@@ -150,7 +167,153 @@ public:
...
@@ -150,7 +167,153 @@ public:
vkDestroyFence
(
device
,
fence
,
nullptr
);
vkDestroyFence
(
device
,
fence
,
nullptr
);
}
}
VulkanExample
()
std
::
tuple
<
VkSemaphore
,
VkSemaphore
,
VkImage
>
render
()
{
/*
Command buffer creation
*/
{
VkCommandBuffer
commandBuffer
;
VkCommandBufferAllocateInfo
cmdBufAllocateInfo
=
vks
::
initializers
::
commandBufferAllocateInfo
(
commandPool
,
VK_COMMAND_BUFFER_LEVEL_PRIMARY
,
1
);
VK_CHECK_RESULT
(
vkAllocateCommandBuffers
(
device
,
&
cmdBufAllocateInfo
,
&
commandBuffer
));
VkCommandBufferBeginInfo
cmdBufInfo
=
vks
::
initializers
::
commandBufferBeginInfo
();
VK_CHECK_RESULT
(
vkBeginCommandBuffer
(
commandBuffer
,
&
cmdBufInfo
));
VkClearValue
clearValues
[
2
];
clearValues
[
0
].
color
=
{
{
0.0f
,
0.0f
,
0.2f
,
1.0f
}
};
clearValues
[
1
].
depthStencil
=
{
1.0f
,
0
};
VkRenderPassBeginInfo
renderPassBeginInfo
=
{};
renderPassBeginInfo
.
sType
=
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
;
renderPassBeginInfo
.
renderArea
.
extent
.
width
=
width
;
renderPassBeginInfo
.
renderArea
.
extent
.
height
=
height
;
renderPassBeginInfo
.
clearValueCount
=
2
;
renderPassBeginInfo
.
pClearValues
=
clearValues
;
renderPassBeginInfo
.
renderPass
=
renderPass
;
renderPassBeginInfo
.
framebuffer
=
framebuffer
;
vkCmdBeginRenderPass
(
commandBuffer
,
&
renderPassBeginInfo
,
VK_SUBPASS_CONTENTS_INLINE
);
VkViewport
viewport
=
{};
viewport
.
height
=
(
float
)
height
;
viewport
.
width
=
(
float
)
width
;
viewport
.
minDepth
=
(
float
)
0.0f
;
viewport
.
maxDepth
=
(
float
)
1.0f
;
vkCmdSetViewport
(
commandBuffer
,
0
,
1
,
&
viewport
);
// Update dynamic scissor state
VkRect2D
scissor
=
{};
scissor
.
extent
.
width
=
width
;
scissor
.
extent
.
height
=
height
;
vkCmdSetScissor
(
commandBuffer
,
0
,
1
,
&
scissor
);
vkCmdBindPipeline
(
commandBuffer
,
VK_PIPELINE_BIND_POINT_GRAPHICS
,
pipeline
);
// Render scene
VkDeviceSize
offsets
[
1
]
=
{
0
};
vkCmdBindVertexBuffers
(
commandBuffer
,
0
,
1
,
&
vertexBuffer
,
offsets
);
vkCmdBindIndexBuffer
(
commandBuffer
,
indexBuffer
,
0
,
VK_INDEX_TYPE_UINT32
);
std
::
vector
<
glm
::
vec3
>
pos
=
{
glm
::
vec3
(
-
1.5f
,
0.0f
,
-
4.0f
),
glm
::
vec3
(
0.0f
,
0.0f
,
-
2.5f
),
glm
::
vec3
(
1.5f
,
0.0f
,
-
4.0f
),
};
for
(
auto
v
:
pos
)
{
glm
::
mat4
mvpMatrix
=
glm
::
perspective
(
glm
::
radians
(
60.0f
),
(
float
)
width
/
(
float
)
height
,
0.1f
,
256.0f
)
*
glm
::
translate
(
glm
::
mat4
(
1.0f
),
v
);
vkCmdPushConstants
(
commandBuffer
,
pipelineLayout
,
VK_SHADER_STAGE_VERTEX_BIT
,
0
,
sizeof
(
mvpMatrix
),
&
mvpMatrix
);
vkCmdDrawIndexed
(
commandBuffer
,
3
,
1
,
0
,
0
,
0
);
}
vkCmdEndRenderPass
(
commandBuffer
);
VK_CHECK_RESULT
(
vkEndCommandBuffer
(
commandBuffer
));
submitWork
(
commandBuffer
,
queue
);
vkDeviceWaitIdle
(
device
);
}
VkImage
dstImage
=
targets_
[
currentTarget
].
image
;
VkSemaphore
presentDone
=
targets_
[
currentTarget
].
presentDone
;
VkSemaphore
renderDone
=
targets_
[
currentTarget
].
renderDone
;
currentTarget
=
(
currentTarget
+
1
)
%
kMaxTargets
;
{
// Do the actual blit from the offscreen image to our host visible destination image
VkCommandBufferAllocateInfo
cmdBufAllocateInfo
=
vks
::
initializers
::
commandBufferAllocateInfo
(
commandPool
,
VK_COMMAND_BUFFER_LEVEL_PRIMARY
,
1
);
VkCommandBuffer
copyCmd
;
VK_CHECK_RESULT
(
vkAllocateCommandBuffers
(
device
,
&
cmdBufAllocateInfo
,
&
copyCmd
));
VkCommandBufferBeginInfo
cmdBufInfo
=
vks
::
initializers
::
commandBufferBeginInfo
();
VK_CHECK_RESULT
(
vkBeginCommandBuffer
(
copyCmd
,
&
cmdBufInfo
));
// Transition destination image to transfer destination layout
vks
::
tools
::
insertImageMemoryBarrier
(
copyCmd
,
dstImage
,
0
,
VK_ACCESS_TRANSFER_WRITE_BIT
,
VK_IMAGE_LAYOUT_UNDEFINED
,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
,
VK_PIPELINE_STAGE_TRANSFER_BIT
,
VK_PIPELINE_STAGE_TRANSFER_BIT
,
VkImageSubresourceRange
{
VK_IMAGE_ASPECT_COLOR_BIT
,
0
,
1
,
0
,
1
});
// colorAttachment.image is already in VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, and does not need to be transitioned
VkImageCopy
imageCopyRegion
{};
imageCopyRegion
.
srcSubresource
.
aspectMask
=
VK_IMAGE_ASPECT_COLOR_BIT
;
imageCopyRegion
.
srcSubresource
.
layerCount
=
1
;
imageCopyRegion
.
dstSubresource
.
aspectMask
=
VK_IMAGE_ASPECT_COLOR_BIT
;
imageCopyRegion
.
dstSubresource
.
layerCount
=
1
;
imageCopyRegion
.
extent
.
width
=
width
;
imageCopyRegion
.
extent
.
height
=
height
;
imageCopyRegion
.
extent
.
depth
=
1
;
vkCmdCopyImage
(
copyCmd
,
colorAttachment
.
image
,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
,
dstImage
,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
,
1
,
&
imageCopyRegion
);
// Transition destination image to general layout, which is the required layout for mapping the image memory later on
vks
::
tools
::
insertImageMemoryBarrier
(
copyCmd
,
dstImage
,
VK_ACCESS_TRANSFER_WRITE_BIT
,
VK_ACCESS_MEMORY_READ_BIT
,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
,
VK_IMAGE_LAYOUT_GENERAL
,
VK_PIPELINE_STAGE_TRANSFER_BIT
,
VK_PIPELINE_STAGE_TRANSFER_BIT
,
VkImageSubresourceRange
{
VK_IMAGE_ASPECT_COLOR_BIT
,
0
,
1
,
0
,
1
});
VK_CHECK_RESULT
(
vkEndCommandBuffer
(
copyCmd
));
// Wait on presentDone and signal renderDone when finished
submitWork
(
copyCmd
,
queue
,
presentDone
,
renderDone
);
vkFreeCommandBuffers
(
device
,
commandPool
,
1
,
&
copyCmd
);
// Get layout of the image (including row pitch)
//VkImageSubresource subResource{};
//subResource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
//VkSubresourceLayout subResourceLayout;
//vkGetImageSubresourceLayout(device, dstImage, &subResource, &subResourceLayout);
//vkDestroyImage(device, dstImage, nullptr);
}
return
std
::
make_tuple
(
renderDone
,
presentDone
,
dstImage
);
}
VulkanExample
(
int32_t
width
,
int32_t
height
)
:
width
(
width
)
,
height
(
height
)
{
{
LOG
(
"Running headless rendering example
\n
"
);
LOG
(
"Running headless rendering example
\n
"
);
...
@@ -358,13 +521,13 @@ public:
...
@@ -358,13 +521,13 @@ public:
vkDestroyBuffer
(
device
,
stagingBuffer
,
nullptr
);
vkDestroyBuffer
(
device
,
stagingBuffer
,
nullptr
);
vkFreeMemory
(
device
,
stagingMemory
,
nullptr
);
vkFreeMemory
(
device
,
stagingMemory
,
nullptr
);
}
}
vkFreeCommandBuffers
(
device
,
commandPool
,
1
,
&
copyCmd
);
}
}
/*
/*
Create framebuffer attachments
Create framebuffer attachments
*/
*/
width
=
1024
;
height
=
1024
;
VkFormat
colorFormat
=
VK_FORMAT_R8G8B8A8_UNORM
;
VkFormat
colorFormat
=
VK_FORMAT_R8G8B8A8_UNORM
;
VkFormat
depthFormat
;
VkFormat
depthFormat
;
vks
::
tools
::
getSupportedDepthFormat
(
physicalDevice
,
&
depthFormat
);
vks
::
tools
::
getSupportedDepthFormat
(
physicalDevice
,
&
depthFormat
);
...
@@ -605,81 +768,34 @@ public:
...
@@ -605,81 +768,34 @@ public:
VK_CHECK_RESULT
(
vkCreateGraphicsPipelines
(
device
,
pipelineCache
,
1
,
&
pipelineCreateInfo
,
nullptr
,
&
pipeline
));
VK_CHECK_RESULT
(
vkCreateGraphicsPipelines
(
device
,
pipelineCache
,
1
,
&
pipelineCreateInfo
,
nullptr
,
&
pipeline
));
}
}
/*
vkQueueWaitIdle
(
queue
);
Command buffer creation
*/
{
VkCommandBuffer
commandBuffer
;
VkCommandBufferAllocateInfo
cmdBufAllocateInfo
=
vks
::
initializers
::
commandBufferAllocateInfo
(
commandPool
,
VK_COMMAND_BUFFER_LEVEL_PRIMARY
,
1
);
VK_CHECK_RESULT
(
vkAllocateCommandBuffers
(
device
,
&
cmdBufAllocateInfo
,
&
commandBuffer
));
VkCommandBufferBeginInfo
cmdBufInfo
=
vks
::
initializers
::
commandBufferBeginInfo
();
VK_CHECK_RESULT
(
vkBeginCommandBuffer
(
commandBuffer
,
&
cmdBufInfo
));
VkClearValue
clearValues
[
2
];
clearValues
[
0
].
color
=
{
{
0.0f
,
0.0f
,
0.2f
,
1.0f
}
};
clearValues
[
1
].
depthStencil
=
{
1.0f
,
0
};
VkRenderPassBeginInfo
renderPassBeginInfo
=
{};
renderPassBeginInfo
.
sType
=
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
;
renderPassBeginInfo
.
renderArea
.
extent
.
width
=
width
;
renderPassBeginInfo
.
renderArea
.
extent
.
height
=
height
;
renderPassBeginInfo
.
clearValueCount
=
2
;
renderPassBeginInfo
.
pClearValues
=
clearValues
;
renderPassBeginInfo
.
renderPass
=
renderPass
;
renderPassBeginInfo
.
framebuffer
=
framebuffer
;
vkCmdBeginRenderPass
(
commandBuffer
,
&
renderPassBeginInfo
,
VK_SUBPASS_CONTENTS_INLINE
);
VkViewport
viewport
=
{};
viewport
.
height
=
(
float
)
height
;
viewport
.
width
=
(
float
)
width
;
viewport
.
minDepth
=
(
float
)
0.0f
;
viewport
.
maxDepth
=
(
float
)
1.0f
;
vkCmdSetViewport
(
commandBuffer
,
0
,
1
,
&
viewport
);
// Update dynamic scissor state
VkRect2D
scissor
=
{};
scissor
.
extent
.
width
=
width
;
scissor
.
extent
.
height
=
height
;
vkCmdSetScissor
(
commandBuffer
,
0
,
1
,
&
scissor
);
vkCmdBindPipeline
(
commandBuffer
,
VK_PIPELINE_BIND_POINT_GRAPHICS
,
pipeline
);
// Render scene
VkDeviceSize
offsets
[
1
]
=
{
0
};
vkCmdBindVertexBuffers
(
commandBuffer
,
0
,
1
,
&
vertexBuffer
,
offsets
);
vkCmdBindIndexBuffer
(
commandBuffer
,
indexBuffer
,
0
,
VK_INDEX_TYPE_UINT32
);
std
::
vector
<
glm
::
vec3
>
pos
=
{
glm
::
vec3
(
-
1.5f
,
0.0f
,
-
4.0f
),
glm
::
vec3
(
0.0f
,
0.0f
,
-
2.5f
),
glm
::
vec3
(
1.5f
,
0.0f
,
-
4.0f
),
};
for
(
auto
v
:
pos
)
{
// Initialize external targets
glm
::
mat4
mvpMatrix
=
glm
::
perspective
(
glm
::
radians
(
60.0f
),
(
float
)
width
/
(
float
)
height
,
0.1f
,
256.0f
)
*
glm
::
translate
(
glm
::
mat4
(
1.0f
),
v
);
for
(
uint32_t
i
=
0
;
i
<
kMaxTargets
;
i
++
)
{
vkCmdPushConstants
(
commandBuffer
,
pipelineLayout
,
VK_SHADER_STAGE_VERTEX_BIT
,
0
,
sizeof
(
mvpMatrix
),
&
mvpMatrix
);
VkSemaphoreTypeCreateInfo
binaryCreateInfo
;
vkCmdDrawIndexed
(
commandBuffer
,
3
,
1
,
0
,
0
,
0
);
binaryCreateInfo
.
sType
=
VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO
;
}
binaryCreateInfo
.
pNext
=
NULL
;
binaryCreateInfo
.
semaphoreType
=
VK_SEMAPHORE_TYPE_BINARY
;
binaryCreateInfo
.
initialValue
=
0
;
vkCmdEndRenderPass
(
commandBuffer
);
VkSemaphoreCreateInfo
createInfo
;
createInfo
.
sType
=
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
;
createInfo
.
pNext
=
&
binaryCreateInfo
;
createInfo
.
flags
=
0
;
VK_CHECK_RESULT
(
vkEndCommandBuffer
(
commandBuffer
));
VkSemaphore
renderDone
;
vkCreateSemaphore
(
device
,
&
createInfo
,
NULL
,
&
renderDone
);
submitWork
(
commandBuffer
,
queue
);
VkSemaphore
presentDone
;
vkCreateSemaphore
(
device
,
&
createInfo
,
NULL
,
&
presentDone
);
vkDeviceWaitIdle
(
device
);
// Signal Semaphore by default to avoid being stuck
}
VkSubmitInfo
submitInfo
;
submitInfo
.
sType
=
VK_STRUCTURE_TYPE_SUBMIT_INFO
;
submitInfo
.
signalSemaphoreCount
=
1
;
submitInfo
.
pSignalSemaphores
=
&
presentDone
;
vkQueueSubmit
(
queue
,
1
,
&
submitInfo
,
VK_NULL_HANDLE
);
/*
Copy framebuffer image to host visible image
*/
const
char
*
imagedata
;
{
// Create the linear tiled destination image to copy to and to read the memory from
// Create the linear tiled destination image to copy to and to read the memory from
VkImageCreateInfo
imgCreateInfo
(
vks
::
initializers
::
imageCreateInfo
());
VkImageCreateInfo
imgCreateInfo
(
vks
::
initializers
::
imageCreateInfo
());
imgCreateInfo
.
imageType
=
VK_IMAGE_TYPE_2D
;
imgCreateInfo
.
imageType
=
VK_IMAGE_TYPE_2D
;
...
@@ -692,135 +808,48 @@ public:
...
@@ -692,135 +808,48 @@ public:
imgCreateInfo
.
initialLayout
=
VK_IMAGE_LAYOUT_UNDEFINED
;
imgCreateInfo
.
initialLayout
=
VK_IMAGE_LAYOUT_UNDEFINED
;
imgCreateInfo
.
samples
=
VK_SAMPLE_COUNT_1_BIT
;
imgCreateInfo
.
samples
=
VK_SAMPLE_COUNT_1_BIT
;
imgCreateInfo
.
tiling
=
VK_IMAGE_TILING_LINEAR
;
imgCreateInfo
.
tiling
=
VK_IMAGE_TILING_LINEAR
;
imgCreateInfo
.
usage
=
VK_IMAGE_USAGE_TRANSFER_DST_BIT
;
imgCreateInfo
.
usage
=
VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
VK_IMAGE_USAGE_SAMPLED_BIT
;
imgCreateInfo
.
sharingMode
=
VK_SHARING_MODE_EXCLUSIVE
;
// Create the image
// Create the image
VkImage
dstImage
;
VkImage
dstImage
;
VK_CHECK_RESULT
(
vkCreateImage
(
device
,
&
imgCreateInfo
,
nullptr
,
&
dstImage
));
VK_CHECK_RESULT
(
vkCreateImage
(
device
,
&
imgCreateInfo
,
nullptr
,
&
dstImage
));
// Create memory to back up the image
// Create memory to back up the image
VkMemoryRequirements
memRequirements
;
VkMemoryRequirements
memRequirements
;
VkMemoryAllocateInfo
memAllocInfo
(
vks
::
initializers
::
memoryAllocateInfo
());
VkMemoryAllocateInfo
memAllocInfo
(
vks
::
initializers
::
memoryAllocateInfo
());
VkDeviceMemory
dstImageMemory
;
VkDeviceMemory
dstImageMemory
;
vkGetImageMemoryRequirements
(
device
,
dstImage
,
&
memRequirements
);
vkGetImageMemoryRequirements
(
device
,
dstImage
,
&
memRequirements
);
memAllocInfo
.
allocationSize
=
memRequirements
.
size
;
memAllocInfo
.
allocationSize
=
memRequirements
.
size
;
// Memory must be host visible to copy from
memAllocInfo
.
memoryTypeIndex
=
getMemoryTypeIndex
(
memRequirements
.
memoryTypeBits
,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
);
memAllocInfo
.
memoryTypeIndex
=
getMemoryTypeIndex
(
memRequirements
.
memoryTypeBits
,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
);
VK_CHECK_RESULT
(
vkAllocateMemory
(
device
,
&
memAllocInfo
,
nullptr
,
&
dstImageMemory
));
VK_CHECK_RESULT
(
vkAllocateMemory
(
device
,
&
memAllocInfo
,
nullptr
,
&
dstImageMemory
));
VK_CHECK_RESULT
(
vkBindImageMemory
(
device
,
dstImage
,
dstImageMemory
,
0
));
VK_CHECK_RESULT
(
vkBindImageMemory
(
device
,
dstImage
,
dstImageMemory
,
0
));
// Do the actual blit from the offscreen image to our host visible destination image
targets_
[
i
].
image
=
dstImage
;
VkCommandBufferAllocateInfo
cmdBufAllocateInfo
=
vks
::
initializers
::
commandBufferAllocateInfo
(
commandPool
,
VK_COMMAND_BUFFER_LEVEL_PRIMARY
,
1
);
targets_
[
i
].
mem
=
dstImageMemory
;
VkCommandBuffer
copyCmd
;
targets_
[
i
].
presentDone
=
presentDone
;
VK_CHECK_RESULT
(
vkAllocateCommandBuffers
(
device
,
&
cmdBufAllocateInfo
,
&
copyCmd
));
targets_
[
i
].
renderDone
=
renderDone
;
VkCommandBufferBeginInfo
cmdBufInfo
=
vks
::
initializers
::
commandBufferBeginInfo
();
VK_CHECK_RESULT
(
vkBeginCommandBuffer
(
copyCmd
,
&
cmdBufInfo
));
// Transition destination image to transfer destination layout
vks
::
tools
::
insertImageMemoryBarrier
(
copyCmd
,
dstImage
,
0
,
VK_ACCESS_TRANSFER_WRITE_BIT
,
VK_IMAGE_LAYOUT_UNDEFINED
,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
,
VK_PIPELINE_STAGE_TRANSFER_BIT
,
VK_PIPELINE_STAGE_TRANSFER_BIT
,
VkImageSubresourceRange
{
VK_IMAGE_ASPECT_COLOR_BIT
,
0
,
1
,
0
,
1
});
// colorAttachment.image is already in VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, and does not need to be transitioned
VkImageCopy
imageCopyRegion
{};
imageCopyRegion
.
srcSubresource
.
aspectMask
=
VK_IMAGE_ASPECT_COLOR_BIT
;
imageCopyRegion
.
srcSubresource
.
layerCount
=
1
;
imageCopyRegion
.
dstSubresource
.
aspectMask
=
VK_IMAGE_ASPECT_COLOR_BIT
;
imageCopyRegion
.
dstSubresource
.
layerCount
=
1
;
imageCopyRegion
.
extent
.
width
=
width
;
imageCopyRegion
.
extent
.
height
=
height
;
imageCopyRegion
.
extent
.
depth
=
1
;
vkCmdCopyImage
(
copyCmd
,
colorAttachment
.
image
,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
,
dstImage
,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
,
1
,
&
imageCopyRegion
);
// Transition destination image to general layout, which is the required layout for mapping the image memory later on
vks
::
tools
::
insertImageMemoryBarrier
(
copyCmd
,
dstImage
,
VK_ACCESS_TRANSFER_WRITE_BIT
,
VK_ACCESS_MEMORY_READ_BIT
,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
,
VK_IMAGE_LAYOUT_GENERAL
,
VK_PIPELINE_STAGE_TRANSFER_BIT
,
VK_PIPELINE_STAGE_TRANSFER_BIT
,
VkImageSubresourceRange
{
VK_IMAGE_ASPECT_COLOR_BIT
,
0
,
1
,
0
,
1
});
VK_CHECK_RESULT
(
vkEndCommandBuffer
(
copyCmd
));
submitWork
(
copyCmd
,
queue
);
// Get layout of the image (including row pitch)
VkImageSubresource
subResource
{};
subResource
.
aspectMask
=
VK_IMAGE_ASPECT_COLOR_BIT
;
VkSubresourceLayout
subResourceLayout
;
vkGetImageSubresourceLayout
(
device
,
dstImage
,
&
subResource
,
&
subResourceLayout
);
// Map image memory so we can start copying from it
vkMapMemory
(
device
,
dstImageMemory
,
0
,
VK_WHOLE_SIZE
,
0
,
(
void
**
)
&
imagedata
);
imagedata
+=
subResourceLayout
.
offset
;
/*
Save host visible framebuffer image to disk (ppm format)
*/
#if defined (VK_USE_PLATFORM_ANDROID_KHR)
const
char
*
filename
=
strcat
(
getenv
(
"EXTERNAL_STORAGE"
),
"/headless.ppm"
);
#else
const
char
*
filename
=
"headless.ppm"
;
#endif
std
::
ofstream
file
(
filename
,
std
::
ios
::
out
|
std
::
ios
::
binary
);
// ppm header
file
<<
"P6
\n
"
<<
width
<<
"
\n
"
<<
height
<<
"
\n
"
<<
255
<<
"
\n
"
;
// If source is BGR (destination is always RGB) and we can't use blit (which does automatic conversion), we'll have to manually swizzle color components
// Check if source is BGR and needs swizzle
std
::
vector
<
VkFormat
>
formatsBGR
=
{
VK_FORMAT_B8G8R8A8_SRGB
,
VK_FORMAT_B8G8R8A8_UNORM
,
VK_FORMAT_B8G8R8A8_SNORM
};
const
bool
colorSwizzle
=
(
std
::
find
(
formatsBGR
.
begin
(),
formatsBGR
.
end
(),
VK_FORMAT_R8G8B8A8_UNORM
)
!=
formatsBGR
.
end
());
// ppm binary pixel data
for
(
int32_t
y
=
0
;
y
<
height
;
y
++
)
{
unsigned
int
*
row
=
(
unsigned
int
*
)
imagedata
;
for
(
int32_t
x
=
0
;
x
<
width
;
x
++
)
{
if
(
colorSwizzle
)
{
file
.
write
((
char
*
)
row
+
2
,
1
);
file
.
write
((
char
*
)
row
+
1
,
1
);
file
.
write
((
char
*
)
row
,
1
);
}
else
{
file
.
write
((
char
*
)
row
,
3
);
}
}
row
++
;
}
imagedata
+=
subResourceLayout
.
rowPitch
;
}
file
.
close
();
LOG
(
"Framebuffer image saved to %s
\n
"
,
filename
);
// Clean up resources
vkUnmapMemory
(
device
,
dstImageMemory
);
vkFreeMemory
(
device
,
dstImageMemory
,
nullptr
);
vkDestroyImage
(
device
,
dstImage
,
nullptr
);
}
vkQueueWaitIdle
(
queue
);
}
}
~
VulkanExample
()
~
VulkanExample
()
{
{
for
(
uint32_t
i
=
0
;
i
<
kMaxTargets
;
i
++
)
{
const
uint64_t
waitValue
=
1
;
VkSemaphoreWaitInfo
waitInfo
;
waitInfo
.
pNext
=
NULL
;
waitInfo
.
flags
=
0
;
waitInfo
.
semaphoreCount
=
1
;
waitInfo
.
pSemaphores
=
&
targets_
[
i
].
presentDone
;
waitInfo
.
pValues
=
&
waitValue
;
vkWaitSemaphores
(
device
,
&
waitInfo
,
UINT64_MAX
);
vkDestroyImage
(
device
,
targets_
[
i
].
image
,
nullptr
);
vkFreeMemory
(
device
,
targets_
[
i
].
mem
,
nullptr
);
vkDestroySemaphore
(
device
,
targets_
[
i
].
renderDone
,
nullptr
);
vkDestroySemaphore
(
device
,
targets_
[
i
].
presentDone
,
nullptr
);
}
vkDestroyBuffer
(
device
,
vertexBuffer
,
nullptr
);
vkDestroyBuffer
(
device
,
vertexBuffer
,
nullptr
);
vkFreeMemory
(
device
,
vertexMemory
,
nullptr
);
vkFreeMemory
(
device
,
vertexMemory
,
nullptr
);
vkDestroyBuffer
(
device
,
indexBuffer
,
nullptr
);
vkDestroyBuffer
(
device
,
indexBuffer
,
nullptr
);
...
@@ -879,11 +908,19 @@ void android_main(android_app* state) {
...
@@ -879,11 +908,19 @@ void android_main(android_app* state) {
}
}
}
}
#else
#else
int
main
()
{
VulkanExample
*
vulkan_example_init
(
int32_t
width
,
int32_t
height
)
{
VulkanExample
*
vulkanExample
=
new
VulkanExample
();
return
new
VulkanExample
(
width
,
height
);
std
::
cout
<<
"Finished. Press enter to terminate..."
;
}
getchar
();
delete
(
vulkanExample
);
std
::
tuple
<
VkSemaphore
,
VkSemaphore
,
VkImage
>
vulkan_example_render
(
VulkanExample
*
vkExInstace
)
{
return
0
;
return
vkExInstace
->
render
();
}
VkDevice
vulkan_example_get_device
(
VulkanExample
*
vkExInstance
)
{
return
vkExInstance
->
device
;
}
void
vulkan_example_deinit
(
VulkanExample
*
vkExInstance
)
{
delete
(
vkExInstance
);
}
}
#endif
#endif
This diff is collapsed.
Click to expand it.
external/Vulkan/examples/renderheadless/renderheadless.h
0 → 100644
+
16
−
0
View file @
a6cbaf15
#pragma once
#include
<vulkan/vulkan.h>
#include
<tuple>
class
VulkanExample
;
VulkanExample
*
vulkan_example_init
(
int32_t
width
,
int32_t
height
);
/* the first semaphore is renderDone, the second semaphore is presentDone */
std
::
tuple
<
VkSemaphore
,
VkSemaphore
,
VkImage
>
vulkan_example_render
(
VulkanExample
*
vkExInstance
);
VkDevice
vulkan_example_get_device
(
VulkanExample
*
vkExInstance
);
void
vulkan_example_deinit
(
VulkanExample
*
vkExInstance
);
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment