mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-10-14 19:27:09 -04:00
Non-Adreno round 4: Mali GPU-drawing block, gamescope YCbCr retry, GL probe, bridge draw sync
- Setup's "Steam interface: GPU drawing" is hidden on Mali and a saved "on" is cleared: with PanVK it rebooted an Edge 60 (G615) as steamwebhelper started. Kept for Xclipse. - gamescope 0130: a composite pipeline refused at start-up is retried with a layout without immutable YCbCr samplers (G615 through Venus refused every composite shader; their SPIR-V has no Float16, so fp16 was not the cause). - Venus: droiddeck-glprobe opens GL through GLX the way the Steam client does, with the loader's reasons logged; when it fails the client's GL goes to llvmpipe. - vkbridge self-test: the draw check waits for the render pass's stores before copying out (a tiler read zeros without the dependency).
This commit is contained in:
1 parent
3ef49faa26
commit
6c8a086190
11 files changed
+203
-5
No files matched your search
@@ -27,6 +27,14 @@ object DeviceSupport {
|
||||
com.droiddeck.launcher.session.SessionPrefs.vkBridge(context)
|
||||
|
||||
/** Whether this phone can use the Mali bridge at all: a Mali (kbase) without a system-driver route. */
|
||||
/** A Mali GPU (its kbase device is there, or the GPU reports a Mali family). Never an Adreno. */
|
||||
fun mali(): Boolean = isMali
|
||||
|
||||
private val isMali by lazy {
|
||||
!adreno() && (File("/dev/mali0").exists() ||
|
||||
com.droiddeck.launcher.gpu.GpuInfo.detect().family.name.startsWith("MALI"))
|
||||
}
|
||||
|
||||
fun bridgeUsable(): Boolean = !adreno() && !SystemVulkanDriver.isAvailable() && File("/dev/mali0").exists()
|
||||
|
||||
/**
|
||||
|
||||
@@ -154,6 +154,7 @@ object SessionFiles {
|
||||
"usr/local/lib/vkbridge/libvulkan_droidbridge.so" to "usr/local/lib/vkbridge/libvulkan_droidbridge.so",
|
||||
"usr/local/share/vkbridge/droidbridge_icd.json" to "usr/local/share/vkbridge/droidbridge_icd.json",
|
||||
"usr/local/bin/droiddeck-vkbridge-smoke" to "usr/local/bin/droiddeck-vkbridge-smoke",
|
||||
"usr/local/bin/droiddeck-glprobe" to "usr/local/bin/droiddeck-glprobe",
|
||||
"usr/local/lib/droiddeck/uruntime" to "usr/local/lib/droiddeck/uruntime",
|
||||
"usr/local/share/licenses/uruntime/LICENSE" to "usr/local/share/licenses/uruntime/LICENSE",
|
||||
) + mangoapp + xclipse.map { it to it } + maliCompat + listOf("comet", "GalaxyCommunication.exe", "update-permissions.exe", "LICENSE", "version").map { "usr/local/lib/droiddeck-comet/$it" to "usr/local/lib/droiddeck-comet/$it" } + msitools.map { it to it } + fexPreloads).filter { (asset, _) ->
|
||||
|
||||
@@ -526,10 +526,23 @@ object SessionPrefs {
|
||||
* Setup's "Steam interface: GPU drawing": with an open driver pair the Steam client composites
|
||||
* its web views in software (stale tiles on RADV/Xclipse); this turns GPU compositing back on.
|
||||
*/
|
||||
fun steamGpuCompositing(context: Context): Boolean = prefs(context).getBoolean("steamGpuCompositing", false)
|
||||
fun steamGpuCompositing(context: Context): Boolean {
|
||||
if (!steamGpuCompositingAllowed()) {
|
||||
// Never on a Mali: with PanVK it rebooted an Edge 60 (G615) twice as steamwebhelper
|
||||
// started. A value saved by the build that offered it is cleared.
|
||||
if (prefs(context).getBoolean("steamGpuCompositing", false))
|
||||
prefs(context).edit().putBoolean("steamGpuCompositing", false).apply()
|
||||
return false
|
||||
}
|
||||
return prefs(context).getBoolean("steamGpuCompositing", false)
|
||||
}
|
||||
|
||||
/** Setup offers "Steam interface: GPU drawing" on Xclipse (RADV) and other non-Mali, non-Adreno GPUs. */
|
||||
fun steamGpuCompositingAllowed(): Boolean =
|
||||
!com.droiddeck.launcher.core.DeviceSupport.adreno() && !com.droiddeck.launcher.core.DeviceSupport.mali()
|
||||
|
||||
fun setSteamGpuCompositing(context: Context, on: Boolean) {
|
||||
prefs(context).edit().putBoolean("steamGpuCompositing", on).apply()
|
||||
prefs(context).edit().putBoolean("steamGpuCompositing", on && steamGpuCompositingAllowed()).apply()
|
||||
}
|
||||
|
||||
fun setVenus(context: Context, on: Boolean) {
|
||||
|
||||
@@ -422,7 +422,7 @@ internal fun SetupPanel(
|
||||
ToggleRow(host, "logs", stringResource(R.string.setup_logs), stringResource(R.string.setup_logs_hint), s.logsEnabled) { a.onLogs() }
|
||||
ToggleRow(host, "agent-commands", stringResource(R.string.setup_agent_commands), null, s.agentCommands) { a.onAgentCommands() }
|
||||
ToggleRow(host, "graphics-logs", stringResource(R.string.setup_graphics_logs), stringResource(R.string.setup_graphics_logs_hint), s.graphicsLogs) { a.onGraphicsLogs() }
|
||||
if (!s.adreno) ToggleRow(host, "steam-gpu-drawing", stringResource(R.string.setup_steam_gpu_drawing), stringResource(R.string.setup_steam_gpu_drawing_hint), s.steamGpuDrawing) { a.onSteamGpuDrawing() }
|
||||
if (!s.adreno && com.droiddeck.launcher.session.SessionPrefs.steamGpuCompositingAllowed()) ToggleRow(host, "steam-gpu-drawing", stringResource(R.string.setup_steam_gpu_drawing), stringResource(R.string.setup_steam_gpu_drawing_hint), s.steamGpuDrawing) { a.onSteamGpuDrawing() }
|
||||
ActionRow(stringResource(R.string.setup_latest_logs), stringResource(R.string.drawer_logs_hint), stringResource(R.string.drawer_share_logs), a.onShareLogs,
|
||||
progress = com.droiddeck.launcher.session.SessionLogShare.progress)
|
||||
ActionRow(stringResource(R.string.setup_saved_logs), stringResource(R.string.setup_saved_logs_hint, com.droiddeck.launcher.session.SessionPaths.KEEP_SESSIONS), stringResource(R.string.setup_clear_logs), a.onClearLogs)
|
||||
|
||||
@@ -681,7 +681,7 @@
|
||||
<string name="setup_agent_commands">Debugging tools</string>
|
||||
<string name="setup_graphics_logs">Detailed graphics logs</string>
|
||||
<string name="setup_steam_gpu_drawing">Steam interface: GPU drawing</string>
|
||||
<string name="setup_steam_gpu_drawing_hint">With a Mali or Xclipse driver pair, Steam draws its pages in software (GPU drawing showed broken tiles). Turn on for a faster Steam interface if it looks right on this phone.</string>
|
||||
<string name="setup_steam_gpu_drawing_hint">With the Xclipse driver pair, Steam draws its pages in software (GPU drawing showed broken tiles). Turn on for a faster Steam interface if it looks right on this phone.</string>
|
||||
<string name="setup_gpu_bridge_fell_back">The Mali bridge failed its self-test on %1$s last session (images or draws), so the session used the PanVK driver pair instead.</string>
|
||||
<string name="setup_graphics_logs_hint">Each game\'s Proton, DXVK and driver logs in the session\'s logs. Always on when the GPU is not an Adreno.</string>
|
||||
<string name="setup_latest_logs">Latest session logs</string>
|
||||
|
||||
@@ -78,3 +78,10 @@ app's Wayland-hosted gamescope never reaches, or need a newer gamescope than the
|
||||
per shader type names the pipeline (shader type, layer count, ycbcr/colorspace masks, fp16) and the
|
||||
SPIR-V capabilities its shader declares. A Mali-G615 through Venus refused all 119 composite
|
||||
pipelines with VK_ERROR_INITIALIZATION_FAILED and nothing said which feature it objected to.
|
||||
- `0130-composite-without-immutable-ycbcr-samplers.patch`: one composite pipeline is compiled at
|
||||
start-up; when the driver refuses it, the descriptor layout is rebuilt without binding 4's immutable
|
||||
YCbCr samplers (that binding then takes the slot's ordinary sampler) and the probe tried again, with
|
||||
both outcomes in the log. `GAMESCOPE_NO_YCBCR_SAMPLERS=1` forces it. A Mali-G615 through Venus
|
||||
refused every composite shader (blit, blur, RCAS: SPIR-V capabilities Shader, Sampled1D,
|
||||
ImageQuery, no Float16) while EASU, NIS and the NV12 converter, which share the layout but never
|
||||
touch binding 4, compiled.
|
||||
@@ -0,0 +1,78 @@
|
||||
diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp
|
||||
index 103baee..d344a99 100644
|
||||
--- a/src/rendervulkan.cpp
|
||||
+++ b/src/rendervulkan.cpp
|
||||
@@ -319,6 +319,33 @@ bool CVulkanDevice::BInit(VkInstance instance, VkSurfaceKHR surface)
|
||||
return false;
|
||||
if (!createShaders())
|
||||
return false;
|
||||
+ {
|
||||
+ // One composite pipeline up front: a driver that refuses it with the immutable YCbCr
|
||||
+ // samplers gets the layout without them (NV12 textures then sample without conversion).
|
||||
+ if ( getenv( "GAMESCOPE_NO_YCBCR_SAMPLERS" ) && *getenv( "GAMESCOPE_NO_YCBCR_SAMPLERS" ) == '1' )
|
||||
+ {
|
||||
+ vk_log.infof( "GAMESCOPE_NO_YCBCR_SAMPLERS=1: composite layout without immutable YCbCr samplers" );
|
||||
+ vk.DestroyPipelineLayout( device(), m_pipelineLayout, nullptr );
|
||||
+ vk.DestroyDescriptorSetLayout( device(), m_descriptorSetLayout, nullptr );
|
||||
+ m_bYcbcrImmutableSamplers = false;
|
||||
+ if ( !createLayouts() )
|
||||
+ return false;
|
||||
+ }
|
||||
+ VkPipeline probe = compilePipeline( 1, 0, SHADER_TYPE_BLIT, 1, 0, 0, 0, false );
|
||||
+ if ( probe == VK_NULL_HANDLE && m_bYcbcrImmutableSamplers )
|
||||
+ {
|
||||
+ vk_log.errorf( "composite pipeline refused; retrying without immutable YCbCr samplers" );
|
||||
+ vk.DestroyPipelineLayout( device(), m_pipelineLayout, nullptr );
|
||||
+ vk.DestroyDescriptorSetLayout( device(), m_descriptorSetLayout, nullptr );
|
||||
+ m_bYcbcrImmutableSamplers = false;
|
||||
+ if ( !createLayouts() )
|
||||
+ return false;
|
||||
+ probe = compilePipeline( 1, 0, SHADER_TYPE_BLIT, 1, 0, 0, 0, false );
|
||||
+ vk_log.infof( "composite pipeline without immutable YCbCr samplers: %s", probe ? "accepted" : "STILL refused" );
|
||||
+ }
|
||||
+ if ( probe != VK_NULL_HANDLE )
|
||||
+ vk.DestroyPipeline( device(), probe, nullptr );
|
||||
+ }
|
||||
if (!createScratchResources())
|
||||
return false;
|
||||
|
||||
@@ -869,7 +896,7 @@ bool CVulkanDevice::createLayouts()
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = VKR_SAMPLER_SLOTS,
|
||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
- .pImmutableSamplers = ycbcrSamplers.data(),
|
||||
+ .pImmutableSamplers = m_bYcbcrImmutableSamplers ? ycbcrSamplers.data() : nullptr,
|
||||
},
|
||||
VkDescriptorSetLayoutBinding {
|
||||
.binding = 5,
|
||||
@@ -1870,6 +1897,8 @@ void CVulkanCmdBuffer::dispatch(uint32_t x, uint32_t y, uint32_t z)
|
||||
imageDescriptors[i].sampler = m_device->sampler(m_samplerState[i]);
|
||||
imageDescriptors[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
ycbcrImageDescriptors[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
+ if ( !m_device->ycbcrImmutableSamplers() )
|
||||
+ ycbcrImageDescriptors[i].sampler = imageDescriptors[i].sampler;
|
||||
if (m_boundTextures[i] == nullptr)
|
||||
continue;
|
||||
|
||||
diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp
|
||||
index 901e6a6..e0ede11 100644
|
||||
--- a/src/rendervulkan.hpp
|
||||
+++ b/src/rendervulkan.hpp
|
||||
@@ -876,6 +876,7 @@ public:
|
||||
inline bool hasDrmPrimaryDevId() {return m_bHasDrmPrimaryDevId;}
|
||||
inline dev_t primaryDevId() {return m_drmPrimaryDevId;}
|
||||
inline bool supportsFp16() {return m_bSupportsFp16;}
|
||||
+ inline bool ycbcrImmutableSamplers() {return m_bYcbcrImmutableSamplers;}
|
||||
inline std::vector<VkExtensionProperties>& supportedExtensions() {return m_supportedExts;}
|
||||
|
||||
inline std::pair<void *, uint32_t> uploadBufferData(uint32_t size)
|
||||
@@ -925,6 +926,9 @@ protected:
|
||||
VkQueue m_generalQueue = nullptr;
|
||||
VkSamplerYcbcrConversion m_ycbcrConversion = VK_NULL_HANDLE;
|
||||
VkSampler m_ycbcrSampler = VK_NULL_HANDLE;
|
||||
+ // Binding 4 carries immutable YCbCr samplers; off when the driver refuses every composite
|
||||
+ // pipeline with them (Mali-G615 through Venus: VK_ERROR_INITIALIZATION_FAILED).
|
||||
+ bool m_bYcbcrImmutableSamplers = true;
|
||||
VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE;
|
||||
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
||||
VkDescriptorPool m_descriptorPool = VK_NULL_HANDLE;
|
||||
@@ -1179,6 +1179,18 @@ BUSCONF
|
||||
) &
|
||||
stop_watcher=$!
|
||||
fi
|
||||
# Mali (Venus): the client's first window needs GL through GLX (Zink). On a Mali-G615 Zink
|
||||
# failed with nothing but "failed to load driver: zink" even with nullDescriptor present, and
|
||||
# the client quit ("UpdateUI GL not available"). One probe the way the client asks, with the
|
||||
# loader's reasons in the log; when GL does not start, the client's GL goes to llvmpipe.
|
||||
if [ "${BL_VENUS:-0}" = 1 ] && [ -x /usr/local/bin/droiddeck-glprobe ] && [ "${GALLIUM_DRIVER:-}" = zink ]; then
|
||||
LIBGL_DEBUG=verbose MESA_LOG_LEVEL=debug timeout 20 /usr/local/bin/droiddeck-glprobe 2>&1 | head -60 | sed 's/^/== glprobe: /'
|
||||
if [ "${PIPESTATUS[0]}" = 1 ]; then
|
||||
export GALLIUM_DRIVER=llvmpipe LIBGL_ALWAYS_SOFTWARE=1
|
||||
unset MESA_LOADER_DRIVER_OVERRIDE LIBGL_KOPPER_DRI2
|
||||
echo "== venus: GL through Zink did not start (see glprobe above); the Steam client's GL uses llvmpipe (software)"
|
||||
fi
|
||||
fi
|
||||
while :; do
|
||||
rm -f "$HOME/.bl-restart-once"
|
||||
if [ -f "$steam_beta" ] && [ "$(cat "$steam_beta" 2>/dev/null)" != "$steam_channel" ]; then
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
# usr/local/lib/vkbridge/libvulkan_droidbridge.so the Vulkan ICD
|
||||
# usr/local/share/vkbridge/droidbridge_icd.json its manifest
|
||||
# usr/local/bin/droiddeck-vkbridge-smoke the session-start self-test
|
||||
# usr/local/bin/droiddeck-glprobe GLX start-up probe (Mali Venus route)
|
||||
set -euo pipefail
|
||||
d=$1
|
||||
cc=${2:-aarch64-linux-gnu-gcc}
|
||||
@@ -20,6 +21,8 @@ mkdir -p "$d/usr/local/lib/vkbridge" "$d/usr/local/share/vkbridge" "$d/usr/local
|
||||
"$strip" --strip-unneeded "$d/usr/local/lib/vkbridge/libvulkan_droidbridge.so"
|
||||
"$cc" -O2 -Wall $inc -I"$here/tests" -o "$d/usr/local/bin/droiddeck-vkbridge-smoke" "$here/tests/smoke.c" -ldl
|
||||
"$strip" --strip-unneeded "$d/usr/local/bin/droiddeck-vkbridge-smoke"
|
||||
"$cc" -O2 -Wall -o "$d/usr/local/bin/droiddeck-glprobe" "$here/tests/glprobe.c" -ldl
|
||||
"$strip" --strip-unneeded "$d/usr/local/bin/droiddeck-glprobe"
|
||||
cat > "$d/usr/local/share/vkbridge/droidbridge_icd.json" <<JSON
|
||||
{"file_format_version": "1.0.0", "ICD": {"library_path": "/usr/local/lib/vkbridge/libvulkan_droidbridge.so", "api_version": "1.4.341"}}
|
||||
JSON
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* droiddeck-glprobe: does OpenGL through GLX start on this session's display, the way the Steam
|
||||
* client's first window asks for it (glXChooseVisual, then a context)? Run once before the client
|
||||
* on the Mali (Venus) route, where Zink failed on a Mali-G615 with nothing but "failed to load
|
||||
* driver: zink" and the client gave up ("UpdateUI GL not available"). Exit 0 when a visual and a
|
||||
* context come back, 1 when GL does not start, 2 when there is no X display or no libGL.
|
||||
* libX11 and libGL are opened at run time, so this builds without their headers.
|
||||
*/
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef void *(*open_display_fn)(const char *);
|
||||
typedef int (*close_display_fn)(void *);
|
||||
typedef int (*default_screen_fn)(void *);
|
||||
typedef void *(*choose_visual_fn)(void *, int, int *);
|
||||
typedef void *(*create_context_fn)(void *, void *, void *, int);
|
||||
typedef void (*destroy_context_fn)(void *, void *);
|
||||
typedef int (*free_fn)(void *);
|
||||
|
||||
#define GLX_RGBA 4
|
||||
#define GLX_DOUBLEBUFFER 5
|
||||
#define GLX_RED_SIZE 8
|
||||
#define GLX_GREEN_SIZE 9
|
||||
#define GLX_BLUE_SIZE 10
|
||||
|
||||
int main(void)
|
||||
{
|
||||
void *x11 = dlopen("libX11.so.6", RTLD_NOW | RTLD_GLOBAL);
|
||||
void *gl = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!x11 || !gl) {
|
||||
printf("glprobe: cannot open %s: %s\n", x11 ? "libGL.so.1" : "libX11.so.6", dlerror());
|
||||
return 2;
|
||||
}
|
||||
open_display_fn open_display = (open_display_fn)dlsym(x11, "XOpenDisplay");
|
||||
close_display_fn close_display = (close_display_fn)dlsym(x11, "XCloseDisplay");
|
||||
default_screen_fn default_screen = (default_screen_fn)dlsym(x11, "XDefaultScreen");
|
||||
free_fn x_free = (free_fn)dlsym(x11, "XFree");
|
||||
choose_visual_fn choose_visual = (choose_visual_fn)dlsym(gl, "glXChooseVisual");
|
||||
create_context_fn create_context = (create_context_fn)dlsym(gl, "glXCreateContext");
|
||||
destroy_context_fn destroy_context = (destroy_context_fn)dlsym(gl, "glXDestroyContext");
|
||||
if (!open_display || !close_display || !default_screen || !x_free || !choose_visual || !create_context ||
|
||||
!destroy_context) {
|
||||
printf("glprobe: missing X11/GLX entry points\n");
|
||||
return 2;
|
||||
}
|
||||
void *dpy = open_display(NULL);
|
||||
if (!dpy) {
|
||||
printf("glprobe: no X display\n");
|
||||
return 2;
|
||||
}
|
||||
int attrs[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, 0};
|
||||
void *visual = choose_visual(dpy, default_screen(dpy), attrs);
|
||||
if (!visual) {
|
||||
printf("glprobe: FAIL glXChooseVisual\n");
|
||||
close_display(dpy);
|
||||
return 1;
|
||||
}
|
||||
void *ctx = create_context(dpy, visual, NULL, 1);
|
||||
x_free(visual);
|
||||
if (!ctx) {
|
||||
printf("glprobe: FAIL glXCreateContext\n");
|
||||
close_display(dpy);
|
||||
return 1;
|
||||
}
|
||||
destroy_context(dpy, ctx);
|
||||
close_display(dpy);
|
||||
printf("glprobe: OK (visual and context)\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -325,7 +325,12 @@ static void test_draw(void)
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL};
|
||||
VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
||||
VkSubpassDescription sub = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, NULL, 1, &ref, NULL, NULL, 0, NULL};
|
||||
VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, NULL, 0, 1, &att, 1, &sub, 0, NULL};
|
||||
/* The copy after the pass reads what the pass stored. Without this dependency the implicit
|
||||
* one to EXTERNAL makes nothing available to transfer reads: a tiler (Mali-G615) wrote the
|
||||
* tile back after the copy had already read zeros ("pixel 0 = 0x00000000"). */
|
||||
VkSubpassDependency dep = {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, 0};
|
||||
VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, NULL, 0, 1, &att, 1, &sub, 1, &dep};
|
||||
VkRenderPass rp;
|
||||
vkCreateRenderPass(dev, &rpci, NULL, &rp);
|
||||
VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, NULL, 0, rp, 1, &view, w, h, 1};
|
||||
@@ -372,6 +377,8 @@ static void test_draw(void)
|
||||
vkCmdPushConstants(cb, pl, VK_SHADER_STAGE_FRAGMENT_BIT, 0, 16, color);
|
||||
vkCmdDraw(cb, 3, 1, 0, 0);
|
||||
vkCmdEndRenderPass(cb);
|
||||
VkMemoryBarrier mb = {VK_STRUCTURE_TYPE_MEMORY_BARRIER, NULL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT};
|
||||
vkCmdPipelineBarrier(cb, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &mb, 0, NULL, 0, NULL);
|
||||
VkBufferImageCopy c = {0, 0, 0, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {w, h, 1}};
|
||||
vkCmdCopyImageToBuffer(cb, img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, rb.buf, 1, &c);
|
||||
int ok = submit(cb);
|
||||
|
||||
Reference in new issue
Block a user