Plumb steamcompmgr window painting to Vulkan compute.

This commit is contained in:
Pierre-Loup A. Griffais 2019-12-10 00:22:43 -08:00 committed by Pierre-Loup A. Griffais
parent 622f198549
commit ec34dad8a9
4 changed files with 163 additions and 124 deletions

View file

@ -1,12 +1,37 @@
[[vk::binding(0, 0)]] RWTexture2D<float4> outImage;
[[vk::binding(1, 0)]] Texture2D inLayerTex0;
[[vk::binding(2, 0)]] SamplerState sampler0;
[[vk::binding(3, 0)]] Texture2D inLayerTex1;
[[vk::binding(4, 0)]] SamplerState sampler1;
[[vk::binding(5, 0)]] Texture2D inLayerTex2;
[[vk::binding(6, 0)]] SamplerState sampler2;
[[vk::binding(7, 0)]] Texture2D inLayerTex3;
[[vk::binding(8, 0)]] SamplerState sampler3;
[[vk::binding(1, 0)]] cbuffer compositeDesc
{
float flLayerCount;
float2 flScale0;
float2 flOffset0;
float flOpacity0;
float2 flScale1;
float2 flOffset1;
float flOpacity1;
float2 flScale2;
float2 flOffset2;
float flOpacity2;
float2 flScale3;
float2 flOffset3;
float flOpacity3;
}
[[vk::binding(2, 0)]] Texture2D inLayerTex0;
[[vk::binding(3, 0)]] SamplerState sampler0;
[[vk::binding(4, 0)]] Texture2D inLayerTex1;
[[vk::binding(5, 0)]] SamplerState sampler1;
[[vk::binding(6, 0)]] Texture2D inLayerTex2;
[[vk::binding(7, 0)]] SamplerState sampler2;
[[vk::binding(8, 0)]] Texture2D inLayerTex3;
[[vk::binding(9, 0)]] SamplerState sampler3;
[numthreads(16, 16, 1)]
void main(
@ -17,7 +42,19 @@ void main(
{
uint2 index = uint2(dispatchThreadId.x, dispatchThreadId.y);
float4 outputValue = inLayerTex0.Sample( sampler0, float2( index ) );
float4 outputValue;
if ( flLayerCount >= 1.0f )
{
outputValue = inLayerTex0.Sample( sampler0, float2( index ) * flScale0 + flOffset0 );
}
if ( flLayerCount >= 2.0f )
{
float4 layerSample = inLayerTex1.Sample( sampler1, float2( index ) * flScale1 + flOffset1 );
float layerAlpha = flOpacity1 * layerSample.a;
outputValue = layerSample * layerAlpha + outputValue * ( 1 - layerAlpha );
}
outImage [index] = outputValue;
}

View file

@ -43,6 +43,10 @@ struct VkPhysicalDeviceMemoryProperties memoryProperties;
int g_nOutImage; // ping/pong between two RTs
CVulkanTexture outputImage[2];
VkBuffer constantBuffer;
VkDeviceMemory bufferMemory;
Composite_t *g_pCompositeBuffer;
std::unordered_map<VulkanTexture_t, CVulkanTexture *> g_mapVulkanTextures;
std::atomic<VulkanTexture_t> g_nMaxVulkanTexHandle;
@ -443,13 +447,17 @@ int init_device()
// probably hard to hit that even with 3 overlays, and a bunch of tracked windows
// famous last words
//#define k_nMaxSets 20
#define k_nMaxSets 2000 // don't have time to cache or free stuff
#define k_nMaxSets 20000 // don't have time to cache or free stuff
VkDescriptorPoolSize descriptorPoolSize[] = {
{
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
k_nMaxSets * 1,
},
{
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
k_nMaxSets * 1,
},
{
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
k_nMaxSets * k_nMaxLayers,
@ -476,7 +484,43 @@ int init_device()
return false;
}
VkBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.pNext = nullptr;
bufferCreateInfo.size = sizeof( Composite_t );
bufferCreateInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
res = vkCreateBuffer( device, &bufferCreateInfo, nullptr, &constantBuffer );
if ( res != VK_SUCCESS )
{
return false;
}
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(device, constantBuffer, &memRequirements);
int memTypeIndex = findMemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT|VK_MEMORY_PROPERTY_HOST_COHERENT_BIT|VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, memRequirements.memoryTypeBits );
if ( memTypeIndex == -1 )
{
return false;
}
VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = memTypeIndex;
vkAllocateMemory( device, &allocInfo, nullptr, &bufferMemory );
vkBindBufferMemory( device, constantBuffer, bufferMemory, 0 );
vkMapMemory( device, bufferMemory, 0, VK_WHOLE_SIZE, 0, (void**)&g_pCompositeBuffer );
if ( g_pCompositeBuffer == nullptr )
{
return false;
}
return true;
}
@ -687,8 +731,11 @@ void vulkan_free_texture( VulkanTexture_t vulkanTex )
// actually free something at some point
}
bool vulkan_composite( struct VulkanPipeline_t *pPipeline )
bool vulkan_composite( struct Composite_t *pComposite, struct VulkanPipeline_t *pPipeline )
{
*g_pCompositeBuffer = *pComposite;
// XXX maybe flush something?
CVulkanTexture *pTex[ k_nMaxLayers ] = {};
uint32_t nTexCount = 0;
@ -714,14 +761,21 @@ bool vulkan_composite( struct VulkanPipeline_t *pPipeline )
vecLayoutBindings.push_back( descriptorSetLayoutBindings ); // first binding is target storage image
descriptorSetLayoutBindings.binding = 1;
descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
vecLayoutBindings.push_back( descriptorSetLayoutBindings ); // second binding is composite description buffer
for ( uint32_t i = 0; i < nTexCount; i++ )
{
descriptorSetLayoutBindings.binding = 2 + ( i * 2 );
descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
descriptorSetLayoutBindings.binding = 1 + ( i * 2 );
vecLayoutBindings.push_back( descriptorSetLayoutBindings );
descriptorSetLayoutBindings.binding = 2 + ( i * 2 ) + 1;
descriptorSetLayoutBindings.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
descriptorSetLayoutBindings.binding = 1 + ( i * 2 ) + 1;
vecLayoutBindings.push_back( descriptorSetLayoutBindings );
}
@ -730,7 +784,7 @@ bool vulkan_composite( struct VulkanPipeline_t *pPipeline )
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.bindingCount = 1 + ( nTexCount * 2 ),
.bindingCount = 2 + ( nTexCount * 2 ),
vecLayoutBindings.data()
};
@ -808,6 +862,12 @@ bool vulkan_composite( struct VulkanPipeline_t *pPipeline )
.imageLayout = VK_IMAGE_LAYOUT_GENERAL
};
VkDescriptorBufferInfo bufferInfo = {
.buffer = constantBuffer,
.offset = 0,
.range = VK_WHOLE_SIZE
};
VkWriteDescriptorSet writeDescriptorSet = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
@ -822,6 +882,13 @@ bool vulkan_composite( struct VulkanPipeline_t *pPipeline )
};
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
writeDescriptorSet.dstBinding = 1;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeDescriptorSet.pImageInfo = nullptr;
writeDescriptorSet.pBufferInfo = &bufferInfo;
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
}
for ( uint32_t i = 0; i < nTexCount; i++ )
@ -857,7 +924,7 @@ bool vulkan_composite( struct VulkanPipeline_t *pPipeline )
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = descriptorSet,
.dstBinding = 1 + (i * 2),
.dstBinding = 2 + (i * 2),
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
@ -878,7 +945,7 @@ bool vulkan_composite( struct VulkanPipeline_t *pPipeline )
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.pNext = nullptr,
.dstSet = descriptorSet,
.dstBinding = 1 + (i * 2) + 1,
.dstBinding = 2 + (i * 2) + 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,

View file

@ -52,12 +52,24 @@ struct VulkanPipeline_t
} layerBindings[ k_nMaxLayers ];
};
struct Composite_t
{
float flLayerCount;
struct
{
float flScaleX, flScaleY;
float flOffsetX, flOffsetY;
float flOpacity;
} layers[ k_nMaxLayers ];
};
int vulkan_init(void);
VulkanTexture_t vulkan_create_texture_from_dmabuf( struct wlr_dmabuf_attributes *pDMA );
void vulkan_free_texture( VulkanTexture_t vulkanTex );
bool vulkan_composite( struct VulkanPipeline_t *pPipeline );
bool vulkan_composite( struct Composite_t *pComposite, struct VulkanPipeline_t *pPipeline );
uint32_t vulkan_get_last_composite_fbid( void );
void vulkan_present_to_window( void );

View file

@ -510,11 +510,10 @@ paint_fake_cursor (Display *dpy, win *w)
}
static void
paint_window (Display *dpy, win *w, Bool doBlend, Bool notificationMode)
paint_window (Display *dpy, win *w, struct Composite_t *pComposite, struct VulkanPipeline_t *pPipeline, Bool notificationMode)
{
int sourceWidth, sourceHeight;
int drawXOffset = 0, drawYOffset = 0;
Bool isScaling = False;
float currentScaleRatio = 1.0;
if (!w)
@ -539,122 +538,57 @@ paint_window (Display *dpy, win *w, Bool doBlend, Bool notificationMode)
sourceHeight = w->a.height;
}
// glBindTexture (GL_TEXTURE_2D, w->texName);
glEnable(GL_TEXTURE_2D);
if (sourceWidth != root_width || sourceHeight != root_height || globalScaleRatio != 1.0f)
if (sourceWidth != g_nOutputWidth || sourceHeight != g_nOutputHeight || globalScaleRatio != 1.0f)
{
float XRatio = (float)root_width / sourceWidth;
float YRatio = (float)root_height / sourceHeight;
float XRatio = (float)g_nOutputWidth / sourceWidth;
float YRatio = (float)g_nOutputHeight / sourceHeight;
currentScaleRatio = (XRatio < YRatio) ? XRatio : YRatio;
currentScaleRatio *= globalScaleRatio;
drawXOffset = (root_width - sourceWidth * currentScaleRatio) / 2.0f;
drawYOffset = (root_height - sourceHeight * currentScaleRatio) / 2.0f;
drawXOffset = (g_nOutputWidth - sourceWidth * currentScaleRatio) / 2.0f;
drawYOffset = (g_nOutputHeight - sourceHeight * currentScaleRatio) / 2.0f;
if ( zoomScaleRatio != 1.0 )
{
drawXOffset += ((sourceWidth / 2) - cursorX) * currentScaleRatio;
drawYOffset += ((sourceHeight / 2) - cursorY) * currentScaleRatio;
}
isScaling = True;
}
if (doBlend)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
int curLayer = (int)pComposite->flLayerCount;
// If scaling and blending, we need to draw our letterbox black border with
// the right opacity instead of relying on the clear color
if (isScaling && doBlend && !notificationMode)
{
glDisable(GL_TEXTURE_2D);
glColor4f(0.0f, 0.0f, 0.0f, (float)w->opacity / OPAQUE);
glBegin (GL_QUADS);
// We can't overdraw because we're blending
// Top and bottom stripes, including sides
if (drawYOffset)
{
glVertex2d (0.0f, 0.0f);
glVertex2d (root_width, 0.0f);
glVertex2d (root_width, drawYOffset);
glVertex2d (0.0f, drawYOffset);
glVertex2d (0.0f, root_height - drawYOffset);
glVertex2d (root_width, root_height - drawYOffset);
glVertex2d (root_width, root_height);
glVertex2d (0.0f, root_height);
}
// Side stripes, excluding any top and bottom areas
if (drawXOffset)
{
glVertex2d (0.0f, drawYOffset);
glVertex2d (drawXOffset, drawYOffset);
glVertex2d (drawXOffset, root_height - drawYOffset);
glVertex2d (0.0f, root_height - drawYOffset);
glVertex2d (root_width - drawXOffset, drawYOffset);
glVertex2d (root_width, drawYOffset);
glVertex2d (root_width, root_height - drawYOffset);
glVertex2d (root_width - drawXOffset, root_height - drawYOffset);
}
glEnd ();
}
pComposite->layers[ curLayer ].flOpacity = (float)w->opacity / OPAQUE;
glEnable(GL_TEXTURE_2D);
if (w->isOverlay)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
else
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
glColor4f(1.0f, 1.0f, 1.0f, (float)w->opacity / OPAQUE);
int originX, originY, width, height;
pComposite->layers[ curLayer ].flScaleX = 1.0 / currentScaleRatio;
pComposite->layers[ curLayer ].flScaleY = 1.0 / currentScaleRatio;
if (notificationMode)
{
int xOffset = 0, yOffset = 0;
width = w->a.width * currentScaleRatio;
height = w->a.height * currentScaleRatio;
int width = w->a.width * currentScaleRatio;
int height = w->a.height * currentScaleRatio;
if (globalScaleRatio != 1.0f)
{
xOffset = (root_width - root_width * globalScaleRatio) / 2.0;
yOffset = (root_height - root_height * globalScaleRatio) / 2.0;
xOffset = (g_nOutputWidth - g_nOutputWidth * globalScaleRatio) / 2.0;
yOffset = (g_nOutputHeight - g_nOutputHeight * globalScaleRatio) / 2.0;
}
originX = root_width - xOffset - width;
originY = root_height - yOffset - height;
pComposite->layers[ curLayer ].flOffsetX = (g_nOutputWidth - xOffset - width) * -1.0f;
pComposite->layers[ curLayer ].flOffsetY = (g_nOutputHeight - yOffset - height) * -1.0f;
}
else
{
originX = drawXOffset;
originY = drawYOffset;
width = sourceWidth * currentScaleRatio;
height = sourceHeight * currentScaleRatio;
pComposite->layers[ curLayer ].flOffsetX = -drawXOffset;
pComposite->layers[ curLayer ].flOffsetY = -drawYOffset;
}
glBegin (GL_QUADS);
glTexCoord2d (0.0f, 0.0f);
glVertex2d (originX, originY);
glTexCoord2d (1.0f, 0.0f);
glVertex2d (originX + width, originY);
glTexCoord2d (1.0f, 1.0f);
glVertex2d (originX + width, originY + height);
glTexCoord2d (0.0f, 1.0f);
glVertex2d (originX, originY + height);
glEnd ();
pPipeline->layerBindings[ curLayer ].tex = w->vulkanTex;
pPipeline->layerBindings[ curLayer ].bFilter = w->isOverlay ? true : false;
pComposite->flLayerCount += 1.0f;
}
static void
@ -768,14 +702,8 @@ paint_all (Display *dpy)
ensure_win_resources(dpy, overlay);
ensure_win_resources(dpy, notification);
glViewport(0, 0, root_width, root_height);
glLoadIdentity();
glOrtho(0.0f, root_width, root_height, 0.0f, -1.0f, 1.0f);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
struct Composite_t composite = {};
struct VulkanPipeline_t pipeline = {};
// Fading out from previous window?
if (fadingOut)
@ -784,7 +712,7 @@ paint_all (Display *dpy)
// Draw it in the background
fadeOutWindow.opacity = (1.0d - newOpacity) * OPAQUE;
paint_window(dpy, &fadeOutWindow, True, False);
paint_window(dpy, &fadeOutWindow, &composite, &pipeline, False);
w = find_win(dpy, currentFocusWindow);
ensure_win_resources(dpy, w);
@ -792,14 +720,14 @@ paint_all (Display *dpy)
// Blend new window on top with linear crossfade
w->opacity = newOpacity * OPAQUE;
paint_window(dpy, w, True, False);
paint_window(dpy, w, &composite, &pipeline, False);
}
else
{
w = find_win(dpy, currentFocusWindow);
ensure_win_resources(dpy, w);
// Just draw focused window as normal, be it Steam or the game
paint_window(dpy, w, False, False);
paint_window(dpy, w, &composite, &pipeline, False);
if (fadeOutWindow.id) {
@ -820,7 +748,7 @@ paint_all (Display *dpy)
{
if (overlay->opacity)
{
paint_window(dpy, overlay, True, False);
paint_window(dpy, overlay, &composite, &pipeline, False);
}
overlay->damaged = 0;
}
@ -829,7 +757,7 @@ paint_all (Display *dpy)
{
if (notification->opacity)
{
paint_window(dpy, notification, True, True);
paint_window(dpy, notification, &composite, &pipeline, True);
}
notification->damaged = 0;
}
@ -843,13 +771,8 @@ paint_all (Display *dpy)
if (drawDebugInfo)
paint_debug_info(dpy);
struct VulkanPipeline_t pipeline = {};
pipeline.layerBindings[0].tex = w->vulkanTex;
pipeline.layerBindings[0].bFilter = false;
bool bResult = vulkan_composite( &pipeline );
bool bResult = vulkan_composite( &composite, &pipeline );
if ( bResult != true )
{