1 #include "main.h"
2 #include "container.h"
3 #include "backend.h"
4 #include "CompositorResource.h"
5 #include "compositor.h"
6 #include "CompositorFont.h"
7 
8 #include <algorithm>
9 #include <cstdlib>
10 #include <limits>
11 #include <sys/shm.h>
12 #include <boost/container_hash/hash.hpp>
13 
14 //#include <gbm.h>
15 #include <fcntl.h>
16 #include <unistd.h>
17 
18 namespace Compositor{
19 
Drawable(Pipeline * pPipeline,CompositorInterface * _pcomp)20 Drawable::Drawable(Pipeline *pPipeline, CompositorInterface *_pcomp) : pcomp(_pcomp), passignedSet(0){
21 	if(!AssignPipeline(pPipeline))
22 		throw Exception("Failed to assign a pipeline");
23 }
24 
~Drawable()25 Drawable::~Drawable(){
26 	for(PipelineDescriptorSet &pipelineDescSet : descSets)
27 		for(uint i = 0; i < Pipeline::SHADER_MODULE_COUNT; ++i)
28 			if(pipelineDescSet.p->pshaderModule[i] && pipelineDescSet.pdescSets[i])
29 				pcomp->ReleaseDescSets(pipelineDescSet.p->pshaderModule[i],pipelineDescSet.pdescSets[i]);
30 }
31 
AssignPipeline(const Pipeline * prenderPipeline)32 bool Drawable::AssignPipeline(const Pipeline *prenderPipeline){
33 	auto m = std::find_if(descSets.begin(),descSets.end(),[&](auto &r)->bool{
34 		return r.p == prenderPipeline && pcomp->frameTag > r.fenceTag+pcomp->swapChainImageCount+1;
35 	});
36 	if(m != descSets.end()){
37 		passignedSet = &(*m);
38 		return true;
39 	}
40 
41 	PipelineDescriptorSet pipelineDescSet;
42 	pipelineDescSet.fenceTag = pcomp->frameTag;
43 	pipelineDescSet.p = prenderPipeline;
44 	for(uint i = 0; i < Pipeline::SHADER_MODULE_COUNT; ++i){
45 		if(!prenderPipeline->pshaderModule[i])
46 			continue;
47 		if(!prenderPipeline->pshaderModule[i] || prenderPipeline->pshaderModule[i]->setCount == 0){
48 			pipelineDescSet.pdescSets[i] = 0;
49 			continue;
50 		}
51 		pipelineDescSet.pdescSets[i] = pcomp->CreateDescSets(prenderPipeline->pshaderModule[i]);
52 		if(!pipelineDescSet.pdescSets[i])
53 			return false;
54 	}
55 	descSets.push_back(pipelineDescSet);
56 	passignedSet = &descSets.back();
57 
58 	return true;
59 }
60 
BindShaderResources(const std::vector<std::pair<ShaderModule::VARIABLE,const void * >> * pVarAddrs,const VkCommandBuffer * pcommandBuffer)61 void Drawable::BindShaderResources(const std::vector<std::pair<ShaderModule::VARIABLE, const void *>> *pVarAddrs, const VkCommandBuffer *pcommandBuffer){
62 	alignas(16) char pushConstantBuffer[128];
63 	for(uint i = 0, p = 0; i < Pipeline::SHADER_MODULE_COUNT; ++i){
64 		//bind descriptor sets
65 		if(!passignedSet->p->pshaderModule[i])
66 			continue;
67 		if(passignedSet->p->pshaderModule[i]->setCount > 0){
68 			vkCmdBindDescriptorSets(*pcommandBuffer,VK_PIPELINE_BIND_POINT_GRAPHICS,passignedSet->p->pipelineLayout,p,passignedSet->p->pshaderModule[i]->setCount,passignedSet->pdescSets[i],0,0);
69 			p += passignedSet->p->pshaderModule[i]->setCount;
70 		}
71 		//copy push constants
72 		for(uint j = 0; j < passignedSet->p->pshaderModule[i]->variables.size(); ++j){
73 			auto m = std::find_if(pVarAddrs->begin(),pVarAddrs->end(),[&](auto &r)->bool{
74 				return (uint)r.first == passignedSet->p->pshaderModule[i]->variables[j].variableMapIndex;
75 			});
76 			if(m == pVarAddrs->end())
77 				continue;
78 			//printf("var: %s, +%u\n",std::get<0>(ShaderModule::variableMap[passignedSet->p->pshaderModule[i]->variables[j].variableMapIndex]),passignedSet->p->pshaderModule[i]->variables[j].offset);
79 			memcpy(pushConstantBuffer+passignedSet->p->pshaderModule[i]->variables[j].offset,
80 				m->second,std::get<1>(ShaderModule::variableMap[passignedSet->p->pshaderModule[i]->variables[j].variableMapIndex]));
81 		}
82 	}
83 
84 	if(passignedSet->p->pushConstantRange.size > 0)
85 		vkCmdPushConstants(*pcommandBuffer,passignedSet->p->pipelineLayout,passignedSet->p->pushConstantRange.stageFlags,passignedSet->p->pushConstantRange.offset,passignedSet->p->pushConstantRange.size,pushConstantBuffer);
86 }
87 
ColorFrame(const char * pshaderName[Pipeline::SHADER_MODULE_COUNT],CompositorInterface * _pcomp)88 ColorFrame::ColorFrame(const char *pshaderName[Pipeline::SHADER_MODULE_COUNT], CompositorInterface *_pcomp) : Drawable(_pcomp->LoadPipeline<ClientPipeline>(pshaderName,0),_pcomp), shaderUserFlags(0), shaderFlags(0), oldShaderFlags(0){
89 	//
90 	clock_gettime(CLOCK_MONOTONIC,&creationTime);
91 }
92 
~ColorFrame()93 ColorFrame::~ColorFrame(){
94 	//
95 }
96 
Draw(const VkRect2D & frame,const glm::vec2 & margin,const glm::vec2 & titlePad,const glm::vec2 & titleSpan,uint stackIndex,uint flags,const VkCommandBuffer * pcommandBuffer)97 void ColorFrame::Draw(const VkRect2D &frame, const glm::vec2 &margin, const glm::vec2 &titlePad, const glm::vec2 &titleSpan, uint stackIndex, uint flags, const VkCommandBuffer *pcommandBuffer){
98 	time = timespec_diff(pcomp->frameTime,creationTime);
99 
100 	glm::vec2 imageExtent = glm::vec2(pcomp->imageExtent.width,pcomp->imageExtent.height);
101 
102 	glm::vec4 frameVec = {frame.offset.x,frame.offset.y,
103 		frame.offset.x+frame.extent.width,frame.offset.y+frame.extent.height};
104 	frameVec = 2.0f*(frameVec+0.5f)/glm::vec4(imageExtent,imageExtent)-1.0f;
105 
106 	std::vector<std::pair<ShaderModule::VARIABLE, const void *>> varAddrs = {
107 		{ShaderModule::VARIABLE_XY0,&frameVec},
108 		{ShaderModule::VARIABLE_XY1,&frameVec.z},
109 		{ShaderModule::VARIABLE_SCREEN,&imageExtent},
110 		{ShaderModule::VARIABLE_MARGIN,&margin},
111 		{ShaderModule::VARIABLE_TITLEPAD,&titlePad},
112 		{ShaderModule::VARIABLE_TITLESPAN,&titleSpan},
113 		{ShaderModule::VARIABLE_STACKINDEX,&stackIndex},
114 		{ShaderModule::VARIABLE_FLAGS,&flags},
115 		{ShaderModule::VARIABLE_TIME,&time}
116 	};
117 	BindShaderResources(&varAddrs,pcommandBuffer);
118 
119 	vkCmdDraw(*pcommandBuffer,1,1,0,0);
120 
121 	passignedSet->fenceTag = pcomp->frameTag;
122 }
123 
ClientFrame(const char * pshaderName[Pipeline::SHADER_MODULE_COUNT],CompositorInterface * _pcomp)124 ClientFrame::ClientFrame(const char *pshaderName[Pipeline::SHADER_MODULE_COUNT], CompositorInterface *_pcomp) : ColorFrame(pshaderName,_pcomp), ptitle(0), fullRegionUpdate(true), animationCompleted(true), enabled(false){
125 	//
126 }
127 
~ClientFrame()128 ClientFrame::~ClientFrame(){
129 	if(ptitle)
130 		delete ptitle;
131 	pcomp->updateQueue.erase(std::remove(pcomp->updateQueue.begin(),pcomp->updateQueue.end(),this),pcomp->updateQueue.end());
132 	pcomp->titleUpdateQueue.erase(std::remove(pcomp->titleUpdateQueue.begin(),pcomp->titleUpdateQueue.end(),this),pcomp->titleUpdateQueue.end());
133 }
134 
Exclude(bool exclude)135 void ClientFrame::Exclude(bool exclude){
136 	//
137 }
138 
CreateSurface(uint w,uint h,uint depth)139 void ClientFrame::CreateSurface(uint w, uint h, uint depth){
140 	pcomp->updateQueue.push_back(this);
141 
142 	surfaceDepth = depth;
143 	ptexture = pcomp->CreateTexture(w,h,surfaceDepth);
144 
145 	UpdateDescSets();
146 }
147 
AdjustSurface(uint w,uint h)148 void ClientFrame::AdjustSurface(uint w, uint h){
149 	pcomp->ReleaseTexture(ptexture);
150 
151 	pcomp->updateQueue.push_back(this);
152 	fullRegionUpdate = true;
153 
154 	ptexture = pcomp->CreateTexture(w,h,surfaceDepth);
155 	//In this case updating the descriptor sets would be enough, but we can't do that because of them being used currently by the pipeline.
156 	if(!AssignPipeline(passignedSet->p))
157 		throw Exception("Failed to assign a pipeline.");
158 	DebugPrintf(stdout,"Texture created: %ux%u\n",w,h);
159 
160 	UpdateDescSets();
161 }
162 
DestroySurface()163 void ClientFrame::DestroySurface(){
164 	//
165 	pcomp->ReleaseTexture(ptexture);
166 }
167 
SetShaders(const char * pshaderName[Pipeline::SHADER_MODULE_COUNT])168 void ClientFrame::SetShaders(const char *pshaderName[Pipeline::SHADER_MODULE_COUNT]){
169 	Pipeline *pPipeline = pcomp->LoadPipeline<ClientPipeline>(pshaderName,0);
170 	if(!AssignPipeline(pPipeline))
171 		throw Exception("Failed to assign a pipeline.");
172 
173 	UpdateDescSets();
174 }
175 
SetTitle(const char * ptext)176 void ClientFrame::SetTitle(const char *ptext){
177 	if(!ptitle){
178 		static const char *pshaderName[Pipeline::SHADER_MODULE_COUNT] = {
179 			"text_vertex.spv",0,"text_fragment.spv"
180 		};
181 		ptitle = new Text(pshaderName,pcomp->ptextEngine);
182 	}
183 	title = ptext;
184 	pcomp->titleUpdateQueue.push_back(this);
185 }
186 
UpdateDescSets()187 void ClientFrame::UpdateDescSets(){
188 	//
189 	VkDescriptorImageInfo descImageInfo = {};
190 	descImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
191 	descImageInfo.imageView = ptexture->imageView;
192 	descImageInfo.sampler = pcomp->pointSampler;
193 
194 	std::vector<VkWriteDescriptorSet> writeDescSets;
195 	for(uint i = 0; i < Pipeline::SHADER_MODULE_COUNT; ++i){
196 		if(!passignedSet->p->pshaderModule[i])
197 			continue;
198 		auto m1 = std::find_if(passignedSet->p->pshaderModule[i]->bindings.begin(),passignedSet->p->pshaderModule[i]->bindings.end(),[&](auto &r)->bool{
199 			return r.type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE && strcmp(r.pname,"content") == 0;
200 		});
201 		if(m1 != passignedSet->p->pshaderModule[i]->bindings.end()){
202 			VkWriteDescriptorSet &writeDescSet = writeDescSets.emplace_back();
203 			writeDescSet = (VkWriteDescriptorSet){};
204 			writeDescSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
205 			writeDescSet.dstSet = passignedSet->pdescSets[i][(*m1).setIndex];
206 			writeDescSet.dstBinding = (*m1).binding;
207 			writeDescSet.dstArrayElement = 0;
208 			writeDescSet.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
209 			writeDescSet.descriptorCount = 1;
210 			writeDescSet.pImageInfo = &descImageInfo;
211 		}
212 
213 		auto m2 = std::find_if(passignedSet->p->pshaderModule[i]->bindings.begin(),passignedSet->p->pshaderModule[i]->bindings.end(),[&](auto &r)->bool{
214 			return r.type == VK_DESCRIPTOR_TYPE_SAMPLER;
215 		});
216 		if(m2 != passignedSet->p->pshaderModule[i]->bindings.end()){
217 			VkWriteDescriptorSet &writeDescSet = writeDescSets.emplace_back();
218 			writeDescSet = (VkWriteDescriptorSet){};
219 			writeDescSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
220 			writeDescSet.dstSet = passignedSet->pdescSets[i][(*m2).setIndex];
221 			writeDescSet.dstBinding = (*m2).binding;
222 			writeDescSet.dstArrayElement = 0;
223 			writeDescSet.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
224 			writeDescSet.descriptorCount = 1;
225 			writeDescSet.pImageInfo = &descImageInfo;
226 		}
227 	}
228 	vkUpdateDescriptorSets(pcomp->logicalDev,writeDescSets.size(),writeDescSets.data(),0,0);
229 }
230 
CompositorInterface(const Configuration * pconfig)231 CompositorInterface::CompositorInterface(const Configuration *pconfig) : physicalDevIndex(pconfig->deviceIndex), currentFrame(0), imageIndex(0), frameTag(0), pcolorBackground(0), pbackground(0), ptextEngine(0), pfsApp(0), pfsAppPrev(0), frameApproval(false), suspended(false), unredirected(false), playingAnimation(false), debugLayers(pconfig->debugLayers), scissoring(pconfig->scissoring), hostMemoryImport(pconfig->hostMemoryImport), unredirOnFullscreen(pconfig->unredirOnFullscreen), enableAnimation(pconfig->enableAnimation), animationDuration(pconfig->animationDuration), pfontName(pconfig->pfontName), fontSize(pconfig->fontSize){
232 	//
233 }
234 
~CompositorInterface()235 CompositorInterface::~CompositorInterface(){
236 	//
237 }
238 
InitializeRenderEngine()239 void CompositorInterface::InitializeRenderEngine(){
240 	uint layerCount;
241 	vkEnumerateInstanceLayerProperties(&layerCount,0);
242 	VkLayerProperties *playerProps = new VkLayerProperties[layerCount];
243 	vkEnumerateInstanceLayerProperties(&layerCount,playerProps);
244 
245 	const char *players[] = {"VK_LAYER_KHRONOS_validation"};
246 	DebugPrintf(stdout,"Enumerating required layers\n");
247 	uint layersFound = 0;
248 	for(uint i = 0; i < layerCount; ++i)
249 		for(uint j = 0; j < sizeof(players)/sizeof(players[0]); ++j)
250 			if(strcmp(playerProps[i].layerName,players[j]) == 0){
251 				printf("  %s\n",players[j]);
252 				++layersFound;
253 			}
254 	if(debugLayers && layersFound < sizeof(players)/sizeof(players[0]))
255 		throw Exception("Could not find all required layers.");
256 
257 	uint extCount;
258 	vkEnumerateInstanceExtensionProperties(0,&extCount,0);
259 	VkExtensionProperties *pextProps = new VkExtensionProperties[extCount];
260 	vkEnumerateInstanceExtensionProperties(0,&extCount,pextProps);
261 
262 	const char *pextensions[] = {
263 		VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
264 		"VK_KHR_surface",
265 		"VK_KHR_xcb_surface",
266 		"VK_KHR_get_physical_device_properties2",
267 		"VK_KHR_external_memory_capabilities"
268 	};
269 	DebugPrintf(stdout,"Enumerating required extensions\n");
270 	uint extFound = 0;
271 	for(uint i = 0; i < extCount; ++i)
272 		for(uint j = 0; j < sizeof(pextensions)/sizeof(pextensions[0]); ++j)
273 			if(strcmp(pextProps[i].extensionName,pextensions[j]) == 0){
274 				printf("  %s\n",pextensions[j]);
275 				++extFound;
276 			}
277 	if(extFound < sizeof(pextensions)/sizeof(pextensions[0]))
278 		throw Exception("Could not find all required extensions.");
279 
280 	VkApplicationInfo appInfo = {};
281 	appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
282 	appInfo.pApplicationName = "chamferwm";
283 	appInfo.applicationVersion = VK_MAKE_VERSION(0,0,1);
284 	appInfo.pEngineName = "chamferwm-engine";
285 	appInfo.engineVersion = VK_MAKE_VERSION(0,0,1);
286 	appInfo.apiVersion = VK_API_VERSION_1_0;
287 
288 	VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = {};
289 	debugUtilsMessengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
290 	debugUtilsMessengerCreateInfo.messageSeverity
291 		 = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
292 		|VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
293 		|VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
294 		|VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
295 	debugUtilsMessengerCreateInfo.messageType
296 		= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
297 		|VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
298 		|VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
299 	debugUtilsMessengerCreateInfo.pfnUserCallback = ValidationLayerDebugCallback2;
300 
301 	VkInstanceCreateInfo instanceCreateInfo = {};
302 	instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
303 	instanceCreateInfo.pApplicationInfo = &appInfo;
304 	if(debugLayers){
305 		DebugPrintf(stdout,"Debug layers enabled.\n");
306 		//also in vkCreateDevice
307 		instanceCreateInfo.enabledLayerCount = sizeof(players)/sizeof(players[0]);
308 		instanceCreateInfo.ppEnabledLayerNames = players;
309 	}else{
310 		instanceCreateInfo.enabledLayerCount = 0;
311 		instanceCreateInfo.ppEnabledLayerNames = 0;
312 	}
313 	instanceCreateInfo.enabledExtensionCount = sizeof(pextensions)/sizeof(pextensions[0]);
314 	instanceCreateInfo.ppEnabledExtensionNames = pextensions;
315 	instanceCreateInfo.pNext = &debugUtilsMessengerCreateInfo;
316 	if(vkCreateInstance(&instanceCreateInfo,0,&instance) != VK_SUCCESS)
317 		throw Exception("Failed to create Vulkan instance.");
318 
319 	//delete []playerProps;
320 	delete []pextProps;
321 
322 	CreateSurfaceKHR(&surface);
323 
324 	VkDebugReportCallbackCreateInfoEXT debugcbCreateInfo = {};
325 	debugcbCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
326 	debugcbCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT|VK_DEBUG_REPORT_WARNING_BIT_EXT;
327 	debugcbCreateInfo.pfnCallback = ValidationLayerDebugCallback;
328 	((PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance,"vkCreateDebugReportCallbackEXT"))(instance,&debugcbCreateInfo,0,&debugReportCb);
329 
330 	DebugPrintf(stdout,"Enumerating physical devices\n");
331 
332 	//physical device
333 	uint devCount;
334 	vkEnumeratePhysicalDevices(instance,&devCount,0);
335 	VkPhysicalDevice *pdevices = new VkPhysicalDevice[devCount];
336 	vkEnumeratePhysicalDevices(instance,&devCount,pdevices);
337 
338 	//VkPhysicalDeviceProperties *pdevProps = new VkPhysicalDeviceProperties[devCount];
339 	VkPhysicalDeviceExternalMemoryHostPropertiesEXT *pPhysicalDeviceExternalMemoryHostProps = new VkPhysicalDeviceExternalMemoryHostPropertiesEXT[devCount];
340 	VkPhysicalDeviceProperties2 *pdevProps = new VkPhysicalDeviceProperties2[devCount];
341 	for(uint i = 0; i < devCount; ++i){
342 		//device properties
343 		pPhysicalDeviceExternalMemoryHostProps[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
344 		pPhysicalDeviceExternalMemoryHostProps[i].pNext = 0;
345 
346 		pdevProps[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
347 		pdevProps[i].pNext = &pPhysicalDeviceExternalMemoryHostProps[i];
348 		vkGetPhysicalDeviceProperties2(pdevices[i],&pdevProps[i]);
349 
350 		//device features
351 		VkPhysicalDeviceFeatures devFeatures;
352 		vkGetPhysicalDeviceFeatures(pdevices[i],&devFeatures);
353 
354 		//extra checks
355 		VkPhysicalDeviceExternalBufferInfo physicalDeviceExternalBufferInfo = {};
356 		physicalDeviceExternalBufferInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO;
357 		physicalDeviceExternalBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
358 		physicalDeviceExternalBufferInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;
359 		VkExternalBufferProperties externalBufferProps = {};
360 		externalBufferProps.sType = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES;
361 		vkGetPhysicalDeviceExternalBufferProperties(pdevices[i],&physicalDeviceExternalBufferInfo,&externalBufferProps);
362 		if((externalBufferProps.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) && (externalBufferProps.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT) == 0 && (externalBufferProps.externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT))
363 			printf("Host pointer import supported!\n");
364 
365 		printf("%c %u: %s\n\t.deviceID: %u\n\t.vendorID: %u\n\t.deviceType: %u\n",
366 			i == physicalDevIndex?'*':' ',
367 			i,pdevProps[i].properties.deviceName,pdevProps[i].properties.deviceID,pdevProps[i].properties.vendorID,pdevProps[i].properties.deviceType);
368 		printf("  max push constant size: %u\n  max bound desc sets: %u\n",
369 			pdevProps[i].properties.limits.maxPushConstantsSize,pdevProps[i].properties.limits.maxBoundDescriptorSets);
370 	}
371 
372 	if(physicalDevIndex >= devCount){
373 		snprintf(Exception::buffer,sizeof(Exception::buffer),"Invalid gpu-index (%u) exceeds the number of available devices (%u).",physicalDevIndex,devCount);
374 		throw Exception();
375 	}
376 
377 	physicalDev = pdevices[physicalDevIndex];
378 	physicalDevExternalMemoryHostProps = pPhysicalDeviceExternalMemoryHostProps[physicalDevIndex];
379 	physicalDevProps = pdevProps[physicalDevIndex].properties;
380 
381 	delete []pdevices;
382 	delete []pdevProps;
383 	delete []pPhysicalDeviceExternalMemoryHostProps;
384 
385 	//VkSurfaceCapabilitiesKHR surfaceCapabilities;
386 	vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDev,surface,&surfaceCapabilities);
387 
388 	uint formatCount;
389 	vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDev,surface,&formatCount,0);
390 	VkSurfaceFormatKHR *pformats = new VkSurfaceFormatKHR[formatCount];
391 	vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDev,surface,&formatCount,pformats);
392 
393 	DebugPrintf(stdout,"Available surface formats: %u\n",formatCount);
394 	for(uint i = 0; i < formatCount; ++i)
395 		if(pformats[i].format == VK_FORMAT_B8G8R8A8_UNORM && pformats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
396 			printf("Surface format ok.\n");
397 
398 	uint presentModeCount;
399 	vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDev,surface,&presentModeCount,0);
400 	VkPresentModeKHR *ppresentModes = new VkPresentModeKHR[presentModeCount];
401 	vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDev,surface,&presentModeCount,ppresentModes);
402 
403 	uint queueFamilyCount;
404 	vkGetPhysicalDeviceQueueFamilyProperties(physicalDev,&queueFamilyCount,0);
405 	VkQueueFamilyProperties *pqueueFamilyProps = new VkQueueFamilyProperties[queueFamilyCount];
406 	vkGetPhysicalDeviceQueueFamilyProperties(physicalDev,&queueFamilyCount,pqueueFamilyProps);
407 
408 	//find required queue families
409 	for(uint i = 0; i < QUEUE_INDEX_COUNT; ++i)
410 		queueFamilyIndex[i] = ~0u;
411 	for(uint i = 0; i < queueFamilyCount; ++i){
412 		if(pqueueFamilyProps[i].queueCount > 0 && pqueueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT){
413 			queueFamilyIndex[QUEUE_INDEX_GRAPHICS] = i;
414 			break;
415 		}
416 	}
417 	for(uint i = 0; i < queueFamilyCount; ++i){
418 		VkBool32 presentSupport;
419 		vkGetPhysicalDeviceSurfaceSupportKHR(physicalDev,i,surface,&presentSupport);
420 
421 		bool compatible = CheckPresentQueueCompatibility(physicalDev,i);
422 		//printf("Device compatibility:\t%u\nPresent support:\t%u\n",compatible,presentSupport);
423 		if(pqueueFamilyProps[i].queueCount > 0 && compatible && presentSupport){
424 			queueFamilyIndex[QUEUE_INDEX_PRESENT] = i;
425 			break;
426 		}
427 	}
428 	/*for(uint i = 0; i < queueFamilyCount; ++i){
429 		if(pqueueFamilyProps[i].queueCount > 0 && pqueueFamilyProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT){
430 			queueFamilyIndex[QUEUE_INDEX_TRANSFER] = i;
431 			break;
432 		}
433 	}*/
434 	std::set<uint> queueSet;
435 	for(uint i = 0; i < QUEUE_INDEX_COUNT; ++i){
436 		if(queueFamilyIndex[i] == ~0u)
437 			throw Exception("No suitable queue family available.");
438 		queueSet.insert(queueFamilyIndex[i]);
439 	}
440 
441 	delete []pqueueFamilyProps;
442 
443 	//queue creation
444 	VkDeviceQueueCreateInfo queueCreateInfo[QUEUE_INDEX_COUNT];
445 	uint queueCount = 0;
446 	for(uint queueFamilyIndex1 : queueSet){
447 		//logical device
448 		static const float queuePriorities[] = {1.0f};
449 		queueCreateInfo[queueCount] = (VkDeviceQueueCreateInfo){};
450 		queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
451 		queueCreateInfo[queueCount].queueFamilyIndex = queueFamilyIndex1;
452 		queueCreateInfo[queueCount].queueCount = 1;
453 		queueCreateInfo[queueCount].pQueuePriorities = queuePriorities;
454 		++queueCount;
455 	}
456 
457 	VkPhysicalDeviceFeatures physicalDevFeatures = {};
458 	physicalDevFeatures.geometryShader = VK_TRUE;
459 	//physicalDevFeatures.multiViewport = VK_TRUE;
460 
461 	uint devExtCount;
462 	vkEnumerateDeviceExtensionProperties(physicalDev,0,&devExtCount,0);
463 	VkExtensionProperties *pdevExtProps = new VkExtensionProperties[devExtCount];
464 	vkEnumerateDeviceExtensionProperties(physicalDev,0,&devExtCount,pdevExtProps);
465 
466 	//device extensions
467 	const char *pdevExtensions[] = {
468 		VK_KHR_SWAPCHAIN_EXTENSION_NAME,
469 		VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
470 		//VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
471 		VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
472 		VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,
473 		VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
474 		VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME
475 		//VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
476 		//VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME,
477 		//VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
478 		//VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
479 		//VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME
480 		//VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME,VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME};
481 	};
482 
483 	DebugPrintf(stdout,"Enumerating required device extensions\n");
484 	uint devExtFound = 0;
485 	for(uint i = 0; i < devExtCount; ++i)
486 		for(uint j = 0; j < sizeof(pdevExtensions)/sizeof(pdevExtensions[0]); ++j)
487 			if(strcmp(pdevExtProps[i].extensionName,pdevExtensions[j]) == 0){
488 				printf("  %s\n",pdevExtensions[j]);
489 				++devExtFound;
490 			}
491 	if(devExtFound < sizeof(pdevExtensions)/sizeof(pdevExtensions[0]))
492 		throw Exception("Could not find all required device extensions.");
493 
494 	VkDeviceCreateInfo devCreateInfo = {};
495 	devCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
496 	devCreateInfo.pQueueCreateInfos = queueCreateInfo;
497 	devCreateInfo.queueCreateInfoCount = queueCount;
498 	devCreateInfo.pEnabledFeatures = &physicalDevFeatures;
499 	devCreateInfo.ppEnabledExtensionNames = pdevExtensions;
500 	devCreateInfo.enabledExtensionCount = sizeof(pdevExtensions)/sizeof(pdevExtensions[0]);
501 	if(debugLayers){
502 		devCreateInfo.ppEnabledLayerNames = players;
503 		devCreateInfo.enabledLayerCount = sizeof(players)/sizeof(players[0]);
504 	}else{
505 		devCreateInfo.ppEnabledLayerNames = 0;
506 		devCreateInfo.enabledLayerCount = 0;
507 	}
508 	if(vkCreateDevice(physicalDev,&devCreateInfo,0,&logicalDev) != VK_SUCCESS)
509 		throw Exception("Failed to create a logical device.");
510 
511 	delete []pdevExtProps;
512 
513 	for(uint i = 0; i < QUEUE_INDEX_COUNT; ++i)
514 		vkGetDeviceQueue(logicalDev,queueFamilyIndex[i],0,&queue[i]);
515 
516 	//render pass (later an array of these for different purposes)
517 	VkAttachmentReference attachmentRef = {};
518 	attachmentRef.attachment = 0;
519 	attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
520 
521 	VkSubpassDescription subpassDesc = {};
522 	subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
523 	subpassDesc.colorAttachmentCount = 1;
524 	subpassDesc.pColorAttachments = &attachmentRef;
525 
526 	VkAttachmentDescription attachmentDesc = {};
527 	attachmentDesc.format = VK_FORMAT_B8G8R8A8_UNORM;
528 	attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
529 	attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;//VK_ATTACHMENT_LOAD_OP_CLEAR;
530 	attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
531 	attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
532 	attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
533 	attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
534 	attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
535 
536 	VkSubpassDependency subpassDependency = {};
537 	subpassDependency.srcSubpass = VK_SUBPASS_EXTERNAL;
538 	subpassDependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
539 	subpassDependency.srcAccessMask = 0;
540 	subpassDependency.dstSubpass = 0;
541 	subpassDependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
542 	subpassDependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
543 	//subpassDependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|VK_ACCESS_MEMORY_READ_BIT;
544 
545 	VkRenderPassCreateInfo renderPassCreateInfo = {};
546 	renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
547 	renderPassCreateInfo.attachmentCount = 1;
548 	renderPassCreateInfo.pAttachments = &attachmentDesc;
549 	renderPassCreateInfo.subpassCount = 1;
550 	renderPassCreateInfo.pSubpasses = &subpassDesc;
551 	renderPassCreateInfo.dependencyCount = 1;
552 	renderPassCreateInfo.pDependencies = &subpassDependency;
553 	if(vkCreateRenderPass(logicalDev,&renderPassCreateInfo,0,&renderPass) != VK_SUCCESS)
554 		throw Exception("Failed to create a render pass.");
555 
556 	InitializeSwapchain();
557 
558 	//sampler
559 	VkSamplerCreateInfo samplerCreateInfo = {};
560 	samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
561 	samplerCreateInfo.magFilter = VK_FILTER_NEAREST;
562 	samplerCreateInfo.minFilter = VK_FILTER_NEAREST;
563 	samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
564 	samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
565 	samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
566 	samplerCreateInfo.anisotropyEnable = VK_FALSE;
567 	samplerCreateInfo.maxAnisotropy = 1;
568 	samplerCreateInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
569 	samplerCreateInfo.unnormalizedCoordinates = VK_FALSE;
570 	samplerCreateInfo.compareEnable = VK_FALSE;
571 	samplerCreateInfo.compareOp = VK_COMPARE_OP_ALWAYS;
572 	samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
573 	samplerCreateInfo.mipLodBias = 0.0f;
574 	samplerCreateInfo.minLod = 0.0f;
575 	samplerCreateInfo.maxLod = 0.0f;
576 	if(vkCreateSampler(logicalDev,&samplerCreateInfo,0,&pointSampler) != VK_SUCCESS)
577 		throw Exception("Failed to create a sampler.");
578 
579 	//descriptor pool
580 	//descriptors of this pool
581 	/*VkDescriptorPoolSize descPoolSizes[2];
582 	descPoolSizes[0] = (VkDescriptorPoolSize){};
583 	descPoolSizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLER;//VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
584 	descPoolSizes[0].descriptorCount = 16;
585 
586 	descPoolSizes[1] = (VkDescriptorPoolSize){};
587 	descPoolSizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
588 	descPoolSizes[1].descriptorCount = 16;
589 
590 	VkDescriptorPoolCreateInfo descPoolCreateInfo = {};
591 	descPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
592 	descPoolCreateInfo.poolSizeCount = sizeof(descPoolSizes)/sizeof(descPoolSizes[0]);
593 	descPoolCreateInfo.pPoolSizes = descPoolSizes;
594 	descPoolCreateInfo.maxSets = 16;
595 	descPoolCreateInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
596 	if(vkCreateDescriptorPool(logicalDev,&descPoolCreateInfo,0,&descPool) != VK_SUCCESS)
597 		throw Exception("Failed to create a descriptor pool.");*/
598 
599 	//command pool and buffers
600 	VkCommandPoolCreateInfo commandPoolCreateInfo = {};
601 	commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
602 	commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex[QUEUE_INDEX_GRAPHICS];
603 	commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
604 	if(vkCreateCommandPool(logicalDev,&commandPoolCreateInfo,0,&commandPool) != VK_SUCCESS)
605 		throw Exception("Failed to create a command pool.");
606 
607 	pcommandBuffers = new VkCommandBuffer[swapChainImageCount];
608 	pcopyCommandBuffers = new VkCommandBuffer[swapChainImageCount];
609 
610 	VkCommandBufferAllocateInfo commandBufferAllocateInfo = {};
611 	commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
612 	commandBufferAllocateInfo.commandPool = commandPool;
613 	commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
614 	commandBufferAllocateInfo.commandBufferCount = swapChainImageCount;
615 	if(vkAllocateCommandBuffers(logicalDev,&commandBufferAllocateInfo,pcommandBuffers) != VK_SUCCESS)
616 		throw Exception("Failed to allocate command buffers.");
617 
618 	if(vkAllocateCommandBuffers(logicalDev,&commandBufferAllocateInfo,pcopyCommandBuffers) != VK_SUCCESS)
619 		throw Exception("Failed to allocate copy command buffer.");
620 
621 	shaders.reserve(1024);
622 	pipelines.reserve(1024);
623 	updateQueue.reserve(1024);
624 	titleUpdateQueue.reserve(1024);
625 	scissorRegions.reserve(32);
626 	presentRectLayers.reserve(32);
627 
628 	ptextEngine = new TextEngine(pfontName,fontSize,this);
629 }
630 
InitializeSwapchain()631 void CompositorInterface::InitializeSwapchain(){
632 	imageExtent = GetExtent();
633 
634 	VkSwapchainCreateInfoKHR swapchainCreateInfo = {};
635 	swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
636 	swapchainCreateInfo.surface = surface;
637 	swapchainCreateInfo.minImageCount = std::max(surfaceCapabilities.minImageCount,3u);
638 	swapchainCreateInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
639 	swapchainCreateInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
640 	swapchainCreateInfo.imageExtent = imageExtent;
641 	swapchainCreateInfo.imageArrayLayers = 1;
642 	swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
643 	if(queueFamilyIndex[QUEUE_INDEX_GRAPHICS] != queueFamilyIndex[QUEUE_INDEX_PRESENT]){
644 		DebugPrintf(stdout,"concurrent swap chain\n");
645 		static const uint queueFamilyIndex1[] = {queueFamilyIndex[QUEUE_INDEX_GRAPHICS],queueFamilyIndex[QUEUE_INDEX_PRESENT]};
646 		swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
647 		swapchainCreateInfo.queueFamilyIndexCount = 2;
648 		swapchainCreateInfo.pQueueFamilyIndices = queueFamilyIndex1;
649 	}else swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
650 	swapchainCreateInfo.preTransform = surfaceCapabilities.currentTransform;
651 	swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
652 	//swapchainCreateInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
653 	swapchainCreateInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
654 	swapchainCreateInfo.clipped = VK_TRUE;
655 	swapchainCreateInfo.oldSwapchain = 0;
656 	if(vkCreateSwapchainKHR(logicalDev,&swapchainCreateInfo,0,&swapChain) != VK_SUCCESS)
657 		throw Exception("Failed to create swap chain.");
658 
659 	DebugPrintf(stdout,"Swap chain image extent %ux%u\n",swapchainCreateInfo.imageExtent.width,swapchainCreateInfo.imageExtent.height);
660 	vkGetSwapchainImagesKHR(logicalDev,swapChain,&swapChainImageCount,0);
661 	pswapChainImages = new VkImage[swapChainImageCount];
662 	vkGetSwapchainImagesKHR(logicalDev,swapChain,&swapChainImageCount,pswapChainImages);
663 
664 	VkImageViewCreateInfo imageViewCreateInfo = {};
665 	imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
666 	imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
667 	imageViewCreateInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
668 	imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
669 	imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
670 	imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
671 	imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
672 	imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
673 	imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
674 	imageViewCreateInfo.subresourceRange.levelCount = 1;
675 	imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
676 	imageViewCreateInfo.subresourceRange.layerCount = 1;
677 	pswapChainImageViews = new VkImageView[swapChainImageCount];
678 	pframebuffers = new VkFramebuffer[swapChainImageCount];
679 	for(uint i = 0; i < swapChainImageCount; ++i){
680 		imageViewCreateInfo.image = pswapChainImages[i];
681 		if(vkCreateImageView(logicalDev,&imageViewCreateInfo,0,&pswapChainImageViews[i]) != VK_SUCCESS)
682 			throw Exception("Failed to create a swap chain image view.");
683 
684 		VkFramebufferCreateInfo framebufferCreateInfo = {};
685 		framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
686 		framebufferCreateInfo.renderPass = renderPass;
687 		framebufferCreateInfo.attachmentCount = 1;
688 		framebufferCreateInfo.pAttachments = &pswapChainImageViews[i];
689 		framebufferCreateInfo.width = imageExtent.width;
690 		framebufferCreateInfo.height = imageExtent.height;
691 		framebufferCreateInfo.layers = 1;
692 		if(vkCreateFramebuffer(logicalDev,&framebufferCreateInfo,0,&pframebuffers[i]) != VK_SUCCESS)
693 			throw Exception("Failed to create a framebuffer.");
694 	}
695 
696 	VkSemaphoreCreateInfo semaphoreCreateInfo = {};
697 	semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
698 
699 	VkFenceCreateInfo fenceCreateInfo = {};
700 	fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
701 	fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
702 
703 	psemaphore = new VkSemaphore[swapChainImageCount][SEMAPHORE_INDEX_COUNT];
704 	pfence = new VkFence[swapChainImageCount];
705 
706 	for(uint i = 0; i < swapChainImageCount; ++i){
707 		if(vkCreateFence(logicalDev,&fenceCreateInfo,0,&pfence[i]) != VK_SUCCESS)
708 			throw Exception("Failed to create a fence.");
709 		for(uint j = 0; j < SEMAPHORE_INDEX_COUNT; ++j)
710 			if(vkCreateSemaphore(logicalDev,&semaphoreCreateInfo,0,&psemaphore[i][j]) != VK_SUCCESS)
711 				throw Exception("Failed to create a semaphore.");
712 	}
713 }
714 
DestroyRenderEngine()715 void CompositorInterface::DestroyRenderEngine(){
716 	DebugPrintf(stdout,"Compositor cleanup\n");
717 
718 	delete ptextEngine;
719 
720 	for(TextureCacheEntry &textureCacheEntry : textureCache)
721 		delete textureCacheEntry.ptexture;
722 
723 	for(auto m : pipelines)
724 		delete m.second;
725 	shaders.clear();
726 
727 	vkFreeCommandBuffers(logicalDev,commandPool,swapChainImageCount,pcommandBuffers);
728 	vkFreeCommandBuffers(logicalDev,commandPool,swapChainImageCount,pcopyCommandBuffers);
729 	delete []pcommandBuffers;
730 	delete []pcopyCommandBuffers;
731 	vkDestroyCommandPool(logicalDev,commandPool,0);
732 
733 	for(VkDescriptorPool &descPool : descPoolArray)
734 		vkDestroyDescriptorPool(logicalDev,descPool,0);
735 	descPoolArray.clear();
736 
737 	vkDestroySampler(logicalDev,pointSampler,0);
738 
739 	DestroySwapchain();
740 
741 	vkDestroyRenderPass(logicalDev,renderPass,0);
742 
743 	vkDestroyDevice(logicalDev,0);
744 
745 	((PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance,"vkDestroyDebugReportCallbackEXT"))(instance,debugReportCb,0);
746 
747 	vkDestroySurfaceKHR(instance,surface,0);
748 	vkDestroyInstance(instance,0);
749 }
750 
DestroySwapchain()751 void CompositorInterface::DestroySwapchain(){
752 	for(uint i = 0; i < swapChainImageCount; ++i){
753 		vkDestroyFence(logicalDev,pfence[i],0);
754 		for(uint j = 0; j < SEMAPHORE_INDEX_COUNT; ++j)
755 			vkDestroySemaphore(logicalDev,psemaphore[i][j],0);
756 
757 		vkDestroyFramebuffer(logicalDev,pframebuffers[i],0);
758 		vkDestroyImageView(logicalDev,pswapChainImageViews[i],0);
759 	}
760 	delete []psemaphore;
761 	delete []pfence;
762 	delete []pswapChainImageViews;
763 	delete []pswapChainImages;
764 	vkDestroySwapchainKHR(logicalDev,swapChain,0);
765 }
766 
AddShader(const char * pname,const Blob * pblob)767 void CompositorInterface::AddShader(const char *pname, const Blob *pblob){
768 	shaders.emplace_back(pname,pblob,this);
769 }
770 
AddDamageRegion(const VkRect2D * prect)771 void CompositorInterface::AddDamageRegion(const VkRect2D *prect){
772 	if(!scissoring)
773 		return;
774 	//find the regions that are completely covered by the param and replace them all with the one larger area
775 	scissorRegions.erase(std::remove_if(scissorRegions.begin(),scissorRegions.end(),[&](auto &scissorRegion)->bool{
776 		return prect->offset.x <= scissorRegion.first.offset.x && prect->offset.y <= scissorRegion.first.offset.y
777 			&& prect->offset.x+prect->extent.width >= scissorRegion.first.offset.x+scissorRegion.first.extent.width
778 			&& prect->offset.y+prect->extent.height >= scissorRegion.first.offset.y+scissorRegion.first.extent.height;
779 	}),scissorRegions.end());
780 	scissorRegions.push_back(std::pair<VkRect2D, uint>(*prect,0));
781 
782 	VkRectLayerKHR &rectLayer = presentRectLayers.emplace_back();
783 	rectLayer.offset = {std::max(prect->offset.x,0),std::max(prect->offset.y,0)};
784 	rectLayer.extent = {
785 		prect->extent.width+std::min((int)imageExtent.width-(rectLayer.offset.x+(int)prect->extent.width),0),
786 		prect->extent.height+std::min((int)imageExtent.height-(rectLayer.offset.y+(int)prect->extent.height),0)
787 	};
788 	rectLayer.layer = 0;
789 }
790 
AddDamageRegion(const WManager::Client * pclient)791 void CompositorInterface::AddDamageRegion(const WManager::Client *pclient){
792 	if(!scissoring)
793 		return;
794 	glm::ivec2 margin = 4*glm::ivec2(
795 		pclient->pcontainer->margin.x*(float)imageExtent.width,
796 		pclient->pcontainer->margin.y*(float)imageExtent.width); //due to aspect, this must be *width
797 
798 	glm::ivec2 titlePad = glm::ivec2(
799 		pclient->pcontainer->titlePad.x*(float)imageExtent.width,
800 		pclient->pcontainer->titlePad.y*(float)imageExtent.width);
801 	glm::ivec2 titlePadOffset = glm::min(titlePad,glm::ivec2(0));
802 	glm::ivec2 titlePadExtent = glm::max(titlePad,glm::ivec2(0));
803 
804 	VkRect2D rect1;
805 	rect1.offset = {pclient->rect.x-margin.x+titlePadOffset.x,pclient->rect.y-margin.y+titlePadOffset.y};
806 	rect1.extent = {pclient->rect.w+2*margin.x-titlePadOffset.x+titlePadExtent.x,pclient->rect.h+2*margin.y-titlePadOffset.y+titlePadExtent.y};
807 	AddDamageRegion(&rect1);
808 	rect1.offset = {pclient->oldRect.x-margin.x+titlePadOffset.x,pclient->oldRect.y-margin.y+titlePadOffset.y};
809 	rect1.extent = {pclient->oldRect.w+2*margin.x-titlePadOffset.x+titlePadExtent.x,pclient->oldRect.h+2*margin.y-titlePadOffset.y+titlePadExtent.y};
810 	AddDamageRegion(&rect1);
811 }
812 
WaitIdle()813 void CompositorInterface::WaitIdle(){
814 	vkDeviceWaitIdle(logicalDev);
815 }
816 
CreateRenderQueueAppendix(const WManager::Client * pclient,const WManager::Container * pfocus)817 void CompositorInterface::CreateRenderQueueAppendix(const WManager::Client *pclient, const WManager::Container *pfocus){
818 	auto s = [&](auto &p)->bool{
819 		return pclient == std::get<0>(p);
820 	};
821 	for(auto m = std::find_if(appendixQueue.begin(),appendixQueue.end(),s);
822 		m != appendixQueue.end(); m = std::find_if(m,appendixQueue.end(),s)){
823 		RenderObject renderObject;
824 		renderObject.pclient = std::get<1>(*m);
825 		renderObject.pclientFrame = std::get<2>(*m);
826 		renderObject.pclientFrame->oldShaderFlags = renderObject.pclientFrame->shaderFlags;
827 		renderObject.pclientFrame->shaderFlags =
828 			(renderObject.pclient->pcontainer == pfocus?ClientFrame::SHADER_FLAG_FOCUS:0)
829 			|(renderObject.pclient->pcontainer->flags & WManager::Container::FLAG_FLOATING?ClientFrame::SHADER_FLAG_FLOATING:0)
830 			//|(renderObject.pclient->pcontainer->pParent && renderObject.pclient->pParent->flags & WManager::Container::FLAG_STACKED?ClientFrame::SHADER_FLAG_STACKED:0)
831 			|renderObject.pclientFrame->shaderUserFlags;
832 		renderQueue.push_back(renderObject);
833 
834 		CreateRenderQueueAppendix(std::get<1>(*m),pfocus);
835 
836 		m = appendixQueue.erase(m);
837 	}
838 }
839 
CreateRenderQueue(const WManager::Container * pcontainer,const WManager::Container * pfocus)840 void CompositorInterface::CreateRenderQueue(const WManager::Container *pcontainer, const WManager::Container *pfocus){
841 	if(!pcontainer->pch)
842 		return; //workaround a bug with stackQueue, need to fix this properly
843 	for(const WManager::Container *pcont : pcontainer->stackQueue){
844 		if(pcont->pclient){
845 			ClientFrame *pclientFrame = dynamic_cast<ClientFrame *>(pcont->pclient);
846 			if(!pclientFrame || (!pclientFrame->enabled && pclientFrame != pfsApp))
847 				continue;
848 
849 			RenderObject renderObject;
850 			renderObject.pclient = pcont->pclient;
851 			renderObject.pclientFrame = pclientFrame;
852 			renderObject.pclientFrame->oldShaderFlags = renderObject.pclientFrame->shaderFlags;
853 			renderObject.pclientFrame->shaderFlags =
854 				(pcont == pfocus || pcontainer == pfocus?ClientFrame::ClientFrame::SHADER_FLAG_FOCUS:0)
855 				//|(renderObject.pclient->pcontainer->flags & WManager::Container::FLAG_FLOATING?ClientFrame::SHADER_FLAG_FLOATING:0) //probably not required here
856 				|(renderObject.pclient->pcontainer->pParent && renderObject.pclient->pcontainer->pParent->flags & WManager::Container::FLAG_STACKED?ClientFrame::SHADER_FLAG_STACKED:0)
857 				|renderObject.pclientFrame->shaderUserFlags;
858 			renderQueue.push_back(renderObject);
859 		}
860 		CreateRenderQueue(pcont,pcontainer == pfocus?pcont:pfocus);
861 	}
862 
863 	if(!pcontainer->pclient)
864 		return;
865 	CreateRenderQueueAppendix(pcontainer->pclient,pfocus);
866 }
867 
PollFrameFence(bool suspend)868 bool CompositorInterface::PollFrameFence(bool suspend){
869 	if(suspend != suspended && !unredirected){
870 		if(suspend)
871 			Suspend();
872 		else Resume();
873 	}
874 	if(unredirOnFullscreen){
875 		if(pfsApp && !unredirected){
876 			DebugPrintf(stdout,"unredirect %p\n",pfsApp);
877 			pfsApp->Exclude(true);
878 			pfsAppPrev = pfsApp;
879 			unredirected = true;
880 			Suspend();
881 		}else
882 		if(!pfsApp && unredirected){
883 			DebugPrintf(stdout,"redirect %p\n",pfsAppPrev);
884 			if(pfsAppPrev){ //may have been closed before leaving fullscreen
885 				pfsAppPrev->Exclude(false);
886 				pfsAppPrev = 0;
887 			}
888 			unredirected = false;
889 			Resume();
890 		}
891 	}
892 
893 	if(suspended && !unredirected)
894 		return false;
895 
896 	frameApproval = false;
897 	if(unredirected)
898 		return true; //let the program proceed to GenerateCommandBuffers (without frameApproval), where the redirection state will be evaluated
899 
900 	for(uint i = 0; i < 3; ++i){
901 		if(vkAcquireNextImageKHR(logicalDev,swapChain,std::numeric_limits<uint64_t>::max(),psemaphore[currentFrame][SEMAPHORE_INDEX_IMAGE_AVAILABLE],0,&imageIndex) != VK_SUCCESS){
902 			DebugPrintf(stderr,"Failed to acquire a swap chain image. Attempting to recreate (%u/3)...\n",i+1);
903 			WaitIdle();
904 			DestroySwapchain();
905 			InitializeSwapchain();
906 			continue;
907 		}
908 		break;
909 	}
910 
911 	if(vkWaitForFences(logicalDev,1,&pfence[currentFrame],VK_TRUE,0) == VK_TIMEOUT)
912 		return false;
913 	vkResetFences(logicalDev,1,&pfence[currentFrame]);
914 
915 	//release the textures no longer in use
916 	textureCache.erase(std::remove_if(textureCache.begin(),textureCache.end(),[&](auto &textureCacheEntry)->bool{
917 		if(frameTag < textureCacheEntry.releaseTag+swapChainImageCount+1 || timespec_diff(frameTime,textureCacheEntry.releaseTime) < 5.0f)
918 			return false;
919 		delete textureCacheEntry.ptexture;
920 		return true;
921 	}),textureCache.end());
922 
923 	descSetCache.erase(std::remove_if(descSetCache.begin(),descSetCache.end(),[&](auto &descSetCacheEntry)->bool{
924 		if(frameTag < descSetCacheEntry.releaseTag+swapChainImageCount+1)
925 			return false;
926 		auto m = std::find_if(descPoolReference.begin(),descPoolReference.end(),[&](auto &p)->bool{
927 			return descSetCacheEntry.pdescSets == p.first;
928 		});
929 		if(m == descPoolReference.end())
930 			return true;
931 		vkFreeDescriptorSets(logicalDev,(*m).second,descSetCacheEntry.setCount,descSetCacheEntry.pdescSets);
932 		descPoolReference.erase(m);
933 		printf("************ releasing desc set\n");
934 
935 		delete []descSetCacheEntry.pdescSets;
936 		return true;
937 	}),descSetCache.end());
938 
939 	ptextEngine->ReleaseCycle();
940 
941 	frameApproval = true;
942 	return true;
943 }
944 
GenerateCommandBuffers(const WManager::Container * proot,const std::vector<std::pair<const WManager::Client *,WManager::Client * >> * pstackAppendix,const WManager::Container * pfocus)945 void CompositorInterface::GenerateCommandBuffers(const WManager::Container *proot, const std::vector<std::pair<const WManager::Client *, WManager::Client *>> *pstackAppendix, const WManager::Container *pfocus){
946 	if(!proot)
947 		return;
948 
949 	//Create a render list elements arranged from back to front
950 	renderQueue.clear();
951 	appendixQueue.clear();
952 	for(auto &p : *pstackAppendix){
953 		ClientFrame *pclientFrame = dynamic_cast<ClientFrame *>(p.second);
954 		if(!pclientFrame || !pclientFrame->enabled)
955 			continue;
956 		if(p.first){
957 			appendixQueue.push_back(AppendixQueueElement(p.first,p.second,pclientFrame));
958 			continue;
959 		}
960 		//desktop features are placed first
961 		RenderObject renderObject;
962 		renderObject.pclient = p.second;
963 		renderObject.pclientFrame = pclientFrame;
964 		renderObject.pclientFrame->oldShaderFlags = renderObject.pclientFrame->shaderFlags;
965 		renderObject.pclientFrame->shaderFlags =
966 			(renderObject.pclient->pcontainer == pfocus?ClientFrame::SHADER_FLAG_FOCUS:0)
967 			|(renderObject.pclient->pcontainer->flags & WManager::Container::FLAG_FLOATING?ClientFrame::SHADER_FLAG_FLOATING:0)
968 			|(renderObject.pclient->pcontainer->pParent && renderObject.pclient->pcontainer->pParent->flags & WManager::Container::FLAG_STACKED?ClientFrame::SHADER_FLAG_STACKED:0)
969 			|renderObject.pclientFrame->shaderUserFlags;
970 		renderQueue.push_back(renderObject);
971 	}
972 
973 	CreateRenderQueue(proot,pfocus);
974 
975 	for(auto m = appendixQueue.begin(); m != appendixQueue.end();){
976 		auto k = std::find_if(appendixQueue.begin(),appendixQueue.end(),[&](auto &p)->bool{
977 			return std::get<0>(*m) == std::get<1>(p);
978 		});
979 		if(k != appendixQueue.end()){
980 			++m;
981 			continue;
982 		}
983 
984 		RenderObject renderObject;
985 		renderObject.pclient = std::get<1>(*m);
986 		renderObject.pclientFrame = std::get<2>(*m);
987 		renderObject.pclientFrame->oldShaderFlags = renderObject.pclientFrame->shaderFlags;
988 		renderObject.pclientFrame->shaderFlags =
989 			(renderObject.pclient->pcontainer == pfocus?ClientFrame::SHADER_FLAG_FOCUS:0)
990 			|(renderObject.pclient->pcontainer->flags & WManager::Container::FLAG_FLOATING?ClientFrame::SHADER_FLAG_FLOATING:0)
991 			|(renderObject.pclient->pcontainer->pParent && renderObject.pclient->pcontainer->pParent->flags & WManager::Container::FLAG_STACKED?ClientFrame::SHADER_FLAG_STACKED:0)
992 			|renderObject.pclientFrame->shaderUserFlags;
993 		renderQueue.push_back(renderObject);
994 
995 		CreateRenderQueueAppendix(std::get<1>(*m),pfocus);
996 
997 		m = appendixQueue.erase(m);
998 	}
999 
1000 	for(auto &p : appendixQueue){ //push the remaining (untransient) windows to the end of the queue
1001 		RenderObject renderObject;
1002 		renderObject.pclient = std::get<1>(p);
1003 		renderObject.pclientFrame = std::get<2>(p);
1004 		renderObject.pclientFrame->oldShaderFlags = renderObject.pclientFrame->shaderFlags;
1005 		renderObject.pclientFrame->shaderFlags =
1006 			(renderObject.pclient->pcontainer == pfocus?ClientFrame::SHADER_FLAG_FOCUS:0)
1007 			|(renderObject.pclient->pcontainer->flags & WManager::Container::FLAG_FLOATING?ClientFrame::SHADER_FLAG_FLOATING:0)
1008 			|(renderObject.pclient->pcontainer->pParent && renderObject.pclient->pcontainer->pParent->flags & WManager::Container::FLAG_STACKED?ClientFrame::SHADER_FLAG_STACKED:0)
1009 			|renderObject.pclientFrame->shaderUserFlags;
1010 		renderQueue.push_back(renderObject);
1011 	}
1012 
1013 	pfsApp = 0;
1014 
1015 	playingAnimation = false;
1016 	clock_gettime(CLOCK_MONOTONIC,&frameTime);
1017 
1018 	for(uint i = 0; i < renderQueue.size(); ++i){
1019 		RenderObject &renderObject = renderQueue[i];
1020 
1021 		float s;
1022 		if(enableAnimation){
1023 			float t = timespec_diff(frameTime,renderObject.pclient->translationTime);
1024 			s = std::clamp(t/animationDuration,0.0f,1.0f);
1025 			s = 1.0f/(1.0f+expf(-10.0f*s+5.0f));
1026 		}else s = 1.0f;
1027 
1028 		glm::vec2 oldRect1 = glm::vec2(renderObject.pclient->oldRect.x,renderObject.pclient->oldRect.y);
1029 		renderObject.pclient->position = oldRect1+s*(glm::vec2(renderObject.pclient->rect.x,renderObject.pclient->rect.y)-oldRect1);
1030 		if(s < 0.99f
1031 			&& (renderObject.pclient->oldRect.x != renderObject.pclient->rect.x || renderObject.pclient->oldRect.y != renderObject.pclient->rect.y)
1032 			&& !(renderObject.pclient->pcontainer->flags & WManager::Container::FLAG_FLOATING)){
1033 			AddDamageRegion(renderObject.pclient); //need to keep adding the client for as long as the animation is playing
1034 
1035 			playingAnimation = true;
1036 			renderObject.pclientFrame->animationCompleted = false;
1037 
1038 		}else
1039 		if(!renderObject.pclientFrame->animationCompleted){
1040 			AddDamageRegion(renderObject.pclient);
1041 			renderObject.pclientFrame->animationCompleted = true;
1042 
1043 			renderObject.pclient->position = glm::vec2(renderObject.pclient->rect.x,renderObject.pclient->rect.y);
1044 
1045 		}else{
1046 			renderObject.pclient->position = glm::vec2(renderObject.pclient->rect.x,renderObject.pclient->rect.y);
1047 
1048 			if(renderObject.pclient->pcontainer->flags & WManager::Container::FLAG_FULLSCREEN)
1049 				pfsApp = renderObject.pclientFrame;
1050 		}
1051 
1052 		if(renderObject.pclientFrame->shaderFlags != renderObject.pclientFrame->oldShaderFlags)
1053 			AddDamageRegion(renderObject.pclient);
1054 	}
1055 
1056 	if(unredirected || !frameApproval)
1057 		return;
1058 
1059 	VkCommandBufferBeginInfo commandBufferBeginInfo = {};
1060 	commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1061 	commandBufferBeginInfo.flags = 0;
1062 	if(vkBeginCommandBuffer(pcopyCommandBuffers[currentFrame],&commandBufferBeginInfo) != VK_SUCCESS)
1063 		throw Exception("Failed to begin command buffer recording.");
1064 
1065 	ClientFrame *pbackground1 = dynamic_cast<ClientFrame *>(pbackground);
1066 	if(pbackground1)
1067 		pbackground1->UpdateContents(&pcopyCommandBuffers[currentFrame]);
1068 
1069 	//TODO: update only visible clients
1070 	for(ClientFrame *pclientFrame : updateQueue)
1071 		pclientFrame->UpdateContents(&pcopyCommandBuffers[currentFrame]);
1072 	updateQueue.clear();
1073 
1074 	for(ClientFrame *pclientFrame : titleUpdateQueue)
1075 		pclientFrame->ptitle->Set(pclientFrame->title.c_str(),&pcopyCommandBuffers[currentFrame]);
1076 	titleUpdateQueue.clear();
1077 
1078 	if(vkEndCommandBuffer(pcopyCommandBuffers[currentFrame]) != VK_SUCCESS)
1079 		throw Exception("Failed to end command buffer recording.");
1080 
1081 	commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
1082 	if(vkBeginCommandBuffer(pcommandBuffers[currentFrame],&commandBufferBeginInfo) != VK_SUCCESS)
1083 		throw Exception("Failed to begin command buffer recording.");
1084 
1085 	//TODO: debug option: draw frames around scissor area
1086 	VkRect2D scissor;
1087 	if(scissoring){
1088 		glm::ivec2 a = glm::ivec2(imageExtent.width,imageExtent.height);
1089 		glm::ivec2 b = glm::ivec2(0);
1090 		for(auto m = scissorRegions.begin(); m != scissorRegions.end();){
1091 			if(((*m).second & 1<<imageIndex) == 0){
1092 				glm::ivec2 a1 = glm::ivec2((*m).first.offset.x,(*m).first.offset.y);
1093 				glm::ivec2 b1 = a1+glm::ivec2((*m).first.extent.width,(*m).first.extent.height);
1094 				a = glm::min(a,a1);
1095 				b = glm::max(b,b1);
1096 
1097 				(*m).second |= 1<<imageIndex;
1098 			}
1099 
1100 			//As soon as the rectangle has been drawn for every image of the swap chain, remove it
1101 			if(~(~0u<<swapChainImageCount) == (*m).second)
1102 				m = scissorRegions.erase(m);
1103 			else ++m;
1104 		}
1105 
1106 		scissor.offset = {std::max(a.x,0),std::max(a.y,0)};
1107 		scissor.extent = {std::max(b.x-scissor.offset.x,0),std::max(b.y-scissor.offset.y,0)};
1108 		vkCmdSetScissor(pcommandBuffers[currentFrame],0,1,&scissor);
1109 	}
1110 
1111 	//static const VkClearValue clearValue = {1.0f,1.0f,1.0f,1.0f};
1112 	VkRenderPassBeginInfo renderPassBeginInfo = {};
1113 	renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1114 	renderPassBeginInfo.renderPass = renderPass;
1115 	renderPassBeginInfo.framebuffer = pframebuffers[imageIndex];
1116 	renderPassBeginInfo.renderArea.offset = {0,0};
1117 	renderPassBeginInfo.renderArea.extent = imageExtent;
1118 	renderPassBeginInfo.clearValueCount = 0;//1;
1119 	renderPassBeginInfo.pClearValues = 0;//&clearValue;
1120 	vkCmdBeginRenderPass(pcommandBuffers[currentFrame],&renderPassBeginInfo,VK_SUBPASS_CONTENTS_INLINE);
1121 
1122 	//clear manually since some parts of the buffer we want to retain based on damage
1123 	if(pbackground){
1124 		vkCmdBindPipeline(pcommandBuffers[currentFrame],VK_PIPELINE_BIND_POINT_GRAPHICS,pbackground->passignedSet->p->pipeline);
1125 
1126 		VkRect2D screenRect;
1127 		screenRect.offset = {0,0};
1128 		screenRect.extent = imageExtent;
1129 		pbackground->Draw(screenRect,glm::vec2(0.0f),glm::vec2(0.0f),glm::vec2(0.0f),0,0,&pcommandBuffers[currentFrame]);
1130 	}
1131 
1132 	//TODO: stencil buffer optimization
1133 
1134 	//for(RenderObject &renderObject : renderQueue){
1135 	for(uint i = 0; i < renderQueue.size(); ++i){
1136 		RenderObject &renderObject = renderQueue[i];
1137 
1138 		if((sint)renderObject.pclient->position.x+renderObject.pclient->rect.w <= 1 || (sint)renderObject.pclient->position.y+renderObject.pclient->rect.h <= 1
1139 			|| (sint)renderObject.pclient->position.x > (sint)imageExtent.width || (sint)renderObject.pclient->position.y > (sint)imageExtent.height)
1140 			continue;
1141 
1142 		VkRect2D frame;
1143 		frame.offset = {(sint)renderObject.pclient->position.x,(sint)renderObject.pclient->position.y};
1144 		frame.extent = {renderObject.pclient->rect.w,renderObject.pclient->rect.h};
1145 		//frame.offset = {renderObject.pclient->rect.x,renderObject.pclient->rect.y};
1146 		//frame.extent = {renderObject.pclient->rect.w,renderObject.pclient->rect.h};
1147 
1148 		/*VkRect2D scissor = frame;
1149 		for(uint j = i+1; j < renderQueue.size(); ++j){
1150 			RenderObject &renderObject1 = renderQueue[j];
1151 
1152 			if(frame.offset.y >= renderObject1.pclient->rect.y-1 &&
1153 				frame.offset.y+frame.extent.height <= renderObject1.pclient->rect.y+renderObject1.pclient->rect.h+1){
1154 				if(scissor.offset.x+scissor.extent.width > renderObject1.pclient->rect.x &&
1155 					scissor.offset.x < renderObject1.pclient->rect.x)
1156 					scissor.extent.width = renderObject1.pclient->rect.x-scissor.offset.x;
1157 
1158 				if(renderObject1.pclient->rect.x+renderObject1.pclient->rect.w > scissor.offset.x &&
1159 					renderObject1.pclient->rect.x < scissor.offset.x){
1160 					sint oldOffset = scissor.offset.x;
1161 					scissor.offset.x = renderObject1.pclient->rect.x+renderObject1.pclient->rect.w;
1162 					scissor.extent.width -= scissor.offset.x-oldOffset;
1163 				}
1164 			}
1165 		}*/
1166 
1167 		vkCmdBindPipeline(pcommandBuffers[currentFrame],VK_PIPELINE_BIND_POINT_GRAPHICS,renderObject.pclientFrame->passignedSet->p->pipeline);
1168 
1169 		renderObject.pclientFrame->Draw(frame,renderObject.pclient->pcontainer->margin,renderObject.pclient->pcontainer->titlePad,renderObject.pclient->pcontainer->titleSpan,renderObject.pclient->stackIndex,renderObject.pclientFrame->shaderFlags,&pcommandBuffers[currentFrame]);
1170 
1171 		if(renderObject.pclient->pcontainer->titleBar != WManager::Container::TITLEBAR_NONE && !(renderObject.pclient->pcontainer->flags & WManager::Container::FLAG_FULLSCREEN) && renderObject.pclientFrame->ptitle){
1172 			glm::uvec2 titlePosition = glm::uvec2(frame.offset.x,frame.offset.y);
1173 			if(renderObject.pclient->titlePad1.x > 1e-5)
1174 				titlePosition.x += frame.extent.width;
1175 			if(renderObject.pclient->titlePad1.y > 1e-5)
1176 				titlePosition.y += frame.extent.height;
1177 			glm::vec2 titlePadAbs = glm::abs(renderObject.pclient->titlePad1);
1178 			if(titlePadAbs.x > titlePadAbs.y){
1179 				titlePosition.y += renderObject.pclient->titleStackOffset.y+renderObject.pclientFrame->ptitle->GetTextLength()-(renderObject.pclientFrame->ptitle->GetTextLength()-renderObject.pclient->titleFrameExtent.y);
1180 				titlePosition.x += (ptextEngine->fontFace->glyph->metrics.horiBearingY>>6)/2;
1181 			}else{
1182 				titlePosition.x += renderObject.pclient->titleStackOffset.x;
1183 				titlePosition.y += (ptextEngine->fontFace->glyph->metrics.horiBearingY>>6)/2;
1184 			}
1185 			titlePosition += 0.5f*renderObject.pclient->titlePad1;
1186 
1187 			//intersect the title region with scissor rectangle
1188 			glm::ivec2 titleRectOffset = glm::ivec2(renderObject.pclient->titleRect.x,renderObject.pclient->titleRect.y);
1189 			glm::ivec2 scissorOffset = glm::ivec2(scissor.offset.x,scissor.offset.y);
1190 			glm::ivec2 offset = glm::max(titleRectOffset,scissorOffset);
1191 			glm::ivec2 extent = glm::min(titleRectOffset+glm::ivec2(renderObject.pclient->titleRect.w,renderObject.pclient->titleRect.h),scissorOffset+glm::ivec2(scissor.extent.width,scissor.extent.height))-offset;
1192 
1193 			if(glm::all(glm::greaterThan(extent,glm::ivec2(0)))){
1194 				VkRect2D textFrame;
1195 				textFrame.offset = {offset.x,offset.y};
1196 				textFrame.extent = {extent.x,extent.y};
1197 
1198 				vkCmdSetScissor(pcommandBuffers[currentFrame],0,1,&textFrame);
1199 
1200 				vkCmdBindPipeline(pcommandBuffers[currentFrame],VK_PIPELINE_BIND_POINT_GRAPHICS,renderObject.pclientFrame->ptitle->passignedSet->p->pipeline);
1201 				//renderObject.pclientFrame->ptitle->Draw(titlePosition,(renderObject.pclient->pcontainer->pParent->flags & WManager::Container::FLAG_STACKED)?renderObject.pclient->pcontainer->pParent->titleTransform:renderObject.pclient->pcontainer->titleTransform,&pcommandBuffers[currentFrame]);
1202 				renderObject.pclientFrame->ptitle->Draw(titlePosition,renderObject.pclient->pcontainer->titleTransform,&pcommandBuffers[currentFrame]);
1203 
1204 				vkCmdSetScissor(pcommandBuffers[currentFrame],0,1,&scissor);
1205 			}
1206 		}
1207 	}
1208 
1209 	vkCmdEndRenderPass(pcommandBuffers[currentFrame]);
1210 
1211 	if(vkEndCommandBuffer(pcommandBuffers[currentFrame]) != VK_SUCCESS)
1212 		throw Exception("Failed to end command buffer recording.");
1213 }
1214 
Present()1215 void CompositorInterface::Present(){
1216 	if(unredirected || !frameApproval)
1217 		return;
1218 
1219 	VkPipelineStageFlags pipelineStageFlags[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
1220 	//VkPipelineStageFlags pipelineStageFlags[] = {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT};
1221 
1222 	VkSubmitInfo submitInfo = {};
1223 	submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1224 	submitInfo.commandBufferCount = 1;
1225 	submitInfo.pCommandBuffers = &pcopyCommandBuffers[currentFrame];
1226 	if(vkQueueSubmit(queue[QUEUE_INDEX_GRAPHICS],1,&submitInfo,0) != VK_SUCCESS)
1227 		throw Exception("Failed to submit a queue.");
1228 
1229 	submitInfo.waitSemaphoreCount = 1;
1230 	submitInfo.pWaitSemaphores = &psemaphore[currentFrame][SEMAPHORE_INDEX_IMAGE_AVAILABLE];
1231 	submitInfo.pWaitDstStageMask = pipelineStageFlags;
1232 	submitInfo.signalSemaphoreCount = 1;
1233 	submitInfo.pSignalSemaphores = &psemaphore[currentFrame][SEMAPHORE_INDEX_RENDER_FINISHED];
1234 	submitInfo.commandBufferCount = 1;
1235 	submitInfo.pCommandBuffers = &pcommandBuffers[currentFrame];
1236 	if(vkQueueSubmit(queue[QUEUE_INDEX_GRAPHICS],1,&submitInfo,pfence[currentFrame]) != VK_SUCCESS)
1237 		throw Exception("Failed to submit a queue.");
1238 
1239 	VkPresentRegionKHR presentRegion = {};
1240 	presentRegion.rectangleCount = presentRectLayers.size();
1241 	presentRegion.pRectangles = presentRectLayers.data();
1242 
1243 	VkPresentRegionsKHR presentRegions = {};
1244 	presentRegions.sType = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR;
1245 	presentRegions.swapchainCount = 1;
1246 	presentRegions.pRegions = &presentRegion;
1247 
1248 	VkPresentInfoKHR presentInfo = {};
1249 	presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
1250 	presentInfo.waitSemaphoreCount = 1;
1251 	presentInfo.pWaitSemaphores = &psemaphore[currentFrame][SEMAPHORE_INDEX_RENDER_FINISHED];
1252 	presentInfo.swapchainCount = 1;
1253 	presentInfo.pSwapchains = &swapChain;
1254 	presentInfo.pImageIndices = &imageIndex;
1255 	presentInfo.pResults = 0;
1256 	presentInfo.pNext = presentRegion.rectangleCount > 0?&presentRegions:0;
1257 	vkQueuePresentKHR(queue[QUEUE_INDEX_PRESENT],&presentInfo);
1258 
1259 	presentRectLayers.clear();
1260 
1261 	currentFrame = (currentFrame+1)%swapChainImageCount;
1262 
1263 	frameTag++;
1264 }
1265 
1266 //-vertex buffer layout is always fixed, since there is no predefined information on what shaders (and thus inputs) will be used on what vertex data
1267 //TODO: take out 'new Pipeline' from below, move it outside - no need to template this
1268 template<class T>
LoadPipeline(const char * pshaderName[Pipeline::SHADER_MODULE_COUNT],const std::vector<std::pair<ShaderModule::INPUT,uint>> * pvertexBufferLayout)1269 Pipeline * CompositorInterface::LoadPipeline(const char *pshaderName[Pipeline::SHADER_MODULE_COUNT], const std::vector<std::pair<ShaderModule::INPUT,uint>> *pvertexBufferLayout){
1270 	size_t hash = typeid(T).hash_code();
1271 	for(uint i = 0; i < Pipeline::SHADER_MODULE_COUNT; ++i)
1272 		if(pshaderName[i])
1273 			boost::hash_combine(hash,std::string(pshaderName[i]));
1274 	if(pvertexBufferLayout)
1275 		boost::hash_range(hash,pvertexBufferLayout->begin(),pvertexBufferLayout->end());
1276 
1277 	auto m = std::find_if(pipelines.begin(),pipelines.end(),[&](auto &r)->bool{
1278 		return r.first == hash;
1279 	});
1280 	if(m != pipelines.end())
1281 		return (*m).second;
1282 
1283 	ShaderModule *pshader[Pipeline::SHADER_MODULE_COUNT] = {};
1284 	for(uint i = 0; i < Pipeline::SHADER_MODULE_COUNT; ++i){
1285 		if(!pshaderName[i])
1286 			continue;
1287 		auto n = std::find_if(shaders.begin(),shaders.end(),[&](auto &r)->bool{
1288 			return strcmp(r.pname,pshaderName[i]) == 0;
1289 		});
1290 		if(n == shaders.end()){
1291 			snprintf(Exception::buffer,sizeof(Exception::buffer),"Shader not found: %s.",pshaderName[i]);
1292 			throw Exception();
1293 		}
1294 		pshader[i] = &(*n);
1295 	}
1296 	Pipeline *pPipeline = new T(
1297 		pshader[Pipeline::SHADER_MODULE_VERTEX],
1298 		pshader[Pipeline::SHADER_MODULE_GEOMETRY],
1299 		pshader[Pipeline::SHADER_MODULE_FRAGMENT],pvertexBufferLayout,this);
1300 	pipelines.push_back(std::pair<size_t, Pipeline *>(hash,pPipeline));
1301 
1302 	return pPipeline;
1303 }
1304 
1305 template Pipeline * CompositorInterface::LoadPipeline<ClientPipeline>(const char *[Pipeline::SHADER_MODULE_COUNT], const std::vector<std::pair<ShaderModule::INPUT,uint>> *);
1306 template Pipeline * CompositorInterface::LoadPipeline<TextPipeline>(const char *[Pipeline::SHADER_MODULE_COUNT], const std::vector<std::pair<ShaderModule::INPUT,uint>> *);
1307 
ClearBackground()1308 void CompositorInterface::ClearBackground(){
1309 	ClientFrame *pbackground1 = dynamic_cast<ClientFrame *>(pbackground);
1310 	if(pbackground1)
1311 		delete pbackground1;
1312 	if(!pcolorBackground){
1313 		static const char *pshaderName[Pipeline::SHADER_MODULE_COUNT] = {
1314 			"default_vertex.spv","default_geometry.spv","solid_fragment.spv"
1315 		};
1316 		pcolorBackground = new ColorFrame(pshaderName,this);
1317 	}
1318 
1319 	pbackground = pcolorBackground;
1320 
1321 	VkRect2D screenRect;
1322 	screenRect.offset = {0,0};
1323 	screenRect.extent = imageExtent;
1324 	AddDamageRegion(&screenRect);
1325 }
1326 
CreateTexture(uint w,uint h,uint surfaceDepth)1327 Texture * CompositorInterface::CreateTexture(uint w, uint h, uint surfaceDepth){
1328 	Texture *ptexture;
1329 
1330 	//should be larger than 0:
1331 	w = std::max(std::min(w,physicalDevProps.limits.maxImageDimension2D),1u);
1332 	h = std::max(std::min(h,physicalDevProps.limits.maxImageDimension2D),1u);
1333 
1334 	const VkComponentMapping *pcomponentMapping = surfaceDepth > 24?&TexturePixmap::pixmapComponentMapping:&TexturePixmap::pixmapComponentMapping24;
1335 	uint componentMappingHash = TextureBase::GetComponentMappingHash(pcomponentMapping);
1336 
1337 	auto m = std::find_if(textureCache.begin(),textureCache.end(),[&](auto &r)->bool{
1338 		//return r.ptexture->w == w && r.ptexture->h == h;
1339 		return r.ptexture->w == w && r.ptexture->h == h && r.ptexture->componentMappingHash == componentMappingHash;
1340 	});
1341 	if(m != textureCache.end()){
1342 		ptexture = (*m).ptexture;
1343 
1344 		std::iter_swap(m,textureCache.end()-1);
1345 		textureCache.pop_back();
1346 		printf("----------- found cached texture\n");
1347 
1348 	}else ptexture = new Texture(w,h,pcomponentMapping,0,this);
1349 
1350 	return ptexture;
1351 }
1352 
ReleaseTexture(Texture * ptexture)1353 void CompositorInterface::ReleaseTexture(Texture *ptexture){
1354 	TextureCacheEntry textureCacheEntry;
1355 	textureCacheEntry.ptexture = ptexture;
1356 	textureCacheEntry.releaseTag = frameTag;
1357 	clock_gettime(CLOCK_MONOTONIC,&textureCacheEntry.releaseTime);
1358 
1359 	textureCache.push_back(textureCacheEntry); //->emplace_back
1360 }
1361 
CreateDescSets(const ShaderModule * pshaderModule)1362 VkDescriptorSet * CompositorInterface::CreateDescSets(const ShaderModule *pshaderModule){
1363 	VkDescriptorSet *pdescSets = new VkDescriptorSet[pshaderModule->setCount];
1364 
1365 	for(VkDescriptorPool &descPool : descPoolArray){
1366 		VkDescriptorSetAllocateInfo descSetAllocateInfo = {};
1367 		descSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
1368 		descSetAllocateInfo.descriptorPool = descPool;
1369 		descSetAllocateInfo.pSetLayouts = pshaderModule->pdescSetLayouts;
1370 		descSetAllocateInfo.descriptorSetCount = pshaderModule->setCount;
1371 		if(vkAllocateDescriptorSets(logicalDev,&descSetAllocateInfo,pdescSets) == VK_SUCCESS){
1372 			descPoolReference.push_back(std::pair<VkDescriptorSet *, VkDescriptorPool>(pdescSets,descPool));
1373 			return pdescSets;
1374 		}
1375 	}
1376 
1377 	VkDescriptorPoolSize descPoolSizes[2];
1378 	descPoolSizes[0] = (VkDescriptorPoolSize){};
1379 	descPoolSizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLER;//VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1380 	descPoolSizes[0].descriptorCount = 16;
1381 
1382 	descPoolSizes[1] = (VkDescriptorPoolSize){};
1383 	descPoolSizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
1384 	descPoolSizes[1].descriptorCount = 16;
1385 
1386 	VkDescriptorPool descPool;
1387 
1388 	//if there are no pools or they are all out of memory, attempt to create a new one
1389 	VkDescriptorPoolCreateInfo descPoolCreateInfo = {};
1390 	descPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1391 	descPoolCreateInfo.poolSizeCount = sizeof(descPoolSizes)/sizeof(descPoolSizes[0]);
1392 	descPoolCreateInfo.pPoolSizes = descPoolSizes;
1393 	descPoolCreateInfo.maxSets = 16;
1394 	descPoolCreateInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
1395 	if(vkCreateDescriptorPool(logicalDev,&descPoolCreateInfo,0,&descPool) != VK_SUCCESS){
1396 		delete []pdescSets;
1397 		return 0;
1398 	}
1399 	descPoolArray.push_front(descPool);
1400 
1401 	VkDescriptorSetAllocateInfo descSetAllocateInfo = {};
1402 	descSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
1403 	descSetAllocateInfo.descriptorPool = descPool;
1404 	descSetAllocateInfo.pSetLayouts = pshaderModule->pdescSetLayouts;
1405 	descSetAllocateInfo.descriptorSetCount = pshaderModule->setCount;
1406 	if(vkAllocateDescriptorSets(logicalDev,&descSetAllocateInfo,pdescSets) == VK_SUCCESS){
1407 		descPoolReference.push_back(std::pair<VkDescriptorSet *, VkDescriptorPool>(pdescSets,descPool));
1408 		return pdescSets;
1409 	}
1410 
1411 	delete []pdescSets;
1412 	return 0;
1413 }
1414 
ReleaseDescSets(const ShaderModule * pshaderModule,VkDescriptorSet * pdescSets)1415 void CompositorInterface::ReleaseDescSets(const ShaderModule *pshaderModule, VkDescriptorSet *pdescSets){
1416 	DescSetCacheEntry descSetCacheEntry;
1417 	descSetCacheEntry.pdescSets = pdescSets;
1418 	descSetCacheEntry.setCount = pshaderModule->setCount;
1419 	descSetCacheEntry.releaseTag = frameTag;
1420 
1421 	descSetCache.push_back(descSetCacheEntry);
1422 }
1423 
ValidationLayerDebugCallback(VkDebugReportFlagsEXT flags,VkDebugReportObjectTypeEXT objType,uint64_t obj,size_t location,int32_t code,const char * playerPrefix,const char * pmsg,void * puserData)1424 VKAPI_ATTR VkBool32 VKAPI_CALL CompositorInterface::ValidationLayerDebugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char *playerPrefix, const char *pmsg, void *puserData){
1425 	DebugPrintf(stdout,"validation layer: %s\n",pmsg);
1426 	return VK_FALSE;
1427 }
1428 
ValidationLayerDebugCallback2(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,VkDebugUtilsMessageTypeFlagsEXT messageType,const VkDebugUtilsMessengerCallbackDataEXT * pdata,void * puserData)1429 VKAPI_ATTR VkBool32 VKAPI_CALL CompositorInterface::ValidationLayerDebugCallback2(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pdata, void *puserData){
1430 	DebugPrintf(stdout,"validation layer2: %s\n",pdata->pMessage);
1431 	return VK_FALSE;
1432 }
1433 
1434 //X11ClientFrame::X11ClientFrame(WManager::Container *pcontainer, const Backend::X11Client::CreateInfo *_pcreateInfo, const char *_pshaderName[Pipeline::SHADER_MODULE_COUNT], CompositorInterface *_pcomp) : X11Client(pcontainer,_pcreateInfo), ClientFrame(_pshaderName,_pcomp){
X11ClientFrame(Backend::X11Container * pcontainer,const Backend::X11Client::CreateInfo * _pcreateInfo,const char * _pshaderName[Pipeline::SHADER_MODULE_COUNT],CompositorInterface * _pcomp)1435 X11ClientFrame::X11ClientFrame(Backend::X11Container *pcontainer, const Backend::X11Client::CreateInfo *_pcreateInfo, const char *_pshaderName[Pipeline::SHADER_MODULE_COUNT], CompositorInterface *_pcomp) : X11Client(pcontainer,_pcreateInfo), ClientFrame(_pshaderName,_pcomp){
1436 	//xcb_composite_redirect_window(pbackend->pcon,window,XCB_COMPOSITE_REDIRECT_MANUAL);
1437 	windowPixmap = xcb_generate_id(pbackend->pcon);
1438 
1439 	Backend::X11Container *proot11 = static_cast<Backend::X11Container *>(pcontainer->GetRoot());
1440 	if(!proot11->noComp){
1441 		Redirect1();
1442 		StartComposition1();
1443 	}
1444 }
1445 
~X11ClientFrame()1446 X11ClientFrame::~X11ClientFrame(){
1447 	StopComposition1();
1448 	Unredirect1();
1449 
1450 	if(this == pcomp->pfsAppPrev)
1451 		pcomp->pfsAppPrev = 0;
1452 	//xcb_composite_unredirect_window(pbackend->pcon,window,XCB_COMPOSITE_REDIRECT_MANUAL);
1453 }
1454 
UpdateContents(const VkCommandBuffer * pcommandBuffer)1455 void X11ClientFrame::UpdateContents(const VkCommandBuffer *pcommandBuffer){
1456 	//
1457 	damageRegions.erase(std::remove_if(damageRegions.begin(),damageRegions.end(),[&](const VkRect2D &rect1)->bool{
1458 		return rect.w < rect1.offset.x+rect1.extent.width || rect.h < rect1.offset.y+rect1.extent.height;
1459 	}),damageRegions.end());
1460 
1461 	if(!fullRegionUpdate && damageRegions.size() == 0)
1462 		return;
1463 
1464 	if(fullRegionUpdate){
1465 		damageRegions.clear();
1466 
1467 		VkRect2D rect1;
1468 		rect1.offset = {0,0};
1469 		rect1.extent = {rect.w,rect.h};
1470 		damageRegions.push_back(rect1);
1471 
1472 		fullRegionUpdate = false;
1473 	}
1474 
1475 	if(!pcomp->hostMemoryImport){
1476 		unsigned char *pdata = (unsigned char *)ptexture->Map();
1477 
1478 		for(VkRect2D &rect1 : damageRegions){
1479 			xcb_shm_get_image_cookie_t imageCookie = xcb_shm_get_image(pbackend->pcon,windowPixmap,rect1.offset.x,rect1.offset.y,rect1.extent.width,rect1.extent.height,~0u,XCB_IMAGE_FORMAT_Z_PIXMAP,segment,0);
1480 
1481 			//wait for the buffers to get updated before copying them
1482 			xcb_shm_get_image_reply_t *pimageReply = xcb_shm_get_image_reply(pbackend->pcon,imageCookie,0);
1483 			xcb_flush(pbackend->pcon);
1484 			free(pimageReply);
1485 
1486 			for(uint y = 0; y < rect1.extent.height; ++y){
1487 				uint offsetDst = 4*(rect.w*(y+rect1.offset.y)+rect1.offset.x);
1488 				uint offsetSrc = 4*(rect1.extent.width*y);
1489 				memcpy(pdata+offsetDst,pchpixels+offsetSrc,4*rect1.extent.width);
1490 			}
1491 
1492 			VkRect2D screenRect;
1493 			screenRect.offset = {(sint)position.x+rect1.offset.x,(sint)position.y+rect1.offset.y};
1494 			screenRect.extent = rect1.extent;
1495 			pcomp->AddDamageRegion(&screenRect);
1496 		}
1497 		ptexture->Unmap(pcommandBuffer,damageRegions.data(),damageRegions.size());
1498 
1499 	}else{
1500 		xcb_shm_get_image_cookie_t imageCookie = xcb_shm_get_image(pbackend->pcon,windowPixmap,0,0,rect.w,rect.h,~0u,XCB_IMAGE_FORMAT_Z_PIXMAP,segment,0); //need to get whole image
1501 
1502 		//wait for the buffers to get updated before copying them
1503 		xcb_shm_get_image_reply_t *pimageReply = xcb_shm_get_image_reply(pbackend->pcon,imageCookie,0);
1504 		xcb_flush(pbackend->pcon);
1505 		free(pimageReply);
1506 
1507 		for(VkRect2D &rect1 : damageRegions){
1508 			VkRect2D screenRect;
1509 			screenRect.offset = {(sint)position.x+rect1.offset.x,(sint)position.y+rect1.offset.y};
1510 			screenRect.extent = rect1.extent;
1511 			pcomp->AddDamageRegion(&screenRect);
1512 		}
1513 
1514 		ptexture->Update(pcommandBuffer,damageRegions.data(),damageRegions.size());
1515 	}
1516 
1517 	damageRegions.clear();
1518 }
1519 
Exclude(bool exclude)1520 void X11ClientFrame::Exclude(bool exclude){
1521 	if(exclude){
1522 		StopComposition1();
1523 		Unredirect1();
1524 	}else{
1525 		Redirect1();
1526 		StartComposition1();
1527 	}
1528 }
1529 
AdjustSurface1()1530 void X11ClientFrame::AdjustSurface1(){
1531 	if(!enabled)
1532 		return;
1533 	if(oldRect.w != rect.w || oldRect.h != rect.h){
1534 		//detach
1535 		if(pcomp->hostMemoryImport)
1536 			ptexture->Detach(pcomp->frameTag);
1537 		xcb_shm_detach(pbackend->pcon,segment);
1538 		shmdt(pchpixels);
1539 
1540 		shmctl(shmid,IPC_RMID,0);
1541 
1542 		//attach
1543 		uint textureSize = rect.w*rect.h*4;
1544 		shmid = shmget(IPC_PRIVATE,(textureSize-1)+pcomp->physicalDevExternalMemoryHostProps.minImportedHostPointerAlignment-(textureSize-1)%pcomp->physicalDevExternalMemoryHostProps.minImportedHostPointerAlignment,IPC_CREAT|0777);
1545 		if(shmid == -1){
1546 			DebugPrintf(stderr,"Failed to allocate shared memory.\n");
1547 			return;
1548 		}
1549 		xcb_shm_attach(pbackend->pcon,segment,shmid,0);
1550 		pchpixels = (unsigned char*)shmat(shmid,0,0);
1551 
1552 		xcb_free_pixmap(pbackend->pcon,windowPixmap);
1553 		xcb_composite_name_window_pixmap(pbackend->pcon,window,windowPixmap);
1554 
1555 		AdjustSurface(rect.w,rect.h);
1556 
1557 		if(pcomp->hostMemoryImport && !ptexture->Attach(pchpixels)){
1558 			DebugPrintf(stderr,"Failed to import host memory. Disabling feature.\n");
1559 			pcomp->hostMemoryImport = false;
1560 		}
1561 
1562 		pcomp->AddDamageRegion(this);
1563 	}else
1564 	if(oldRect.x != rect.x || oldRect.y != rect.y)
1565 		pcomp->AddDamageRegion(this);
1566 }
1567 
Redirect1()1568 void X11ClientFrame::Redirect1(){
1569 	//
1570 	xcb_composite_redirect_window(pbackend->pcon,window,XCB_COMPOSITE_REDIRECT_MANUAL);
1571 }
1572 
StartComposition1()1573 void X11ClientFrame::StartComposition1(){
1574 	if(enabled)
1575 		return;
1576 	xcb_composite_name_window_pixmap(pbackend->pcon,window,windowPixmap);
1577 
1578 	damage = xcb_generate_id(pbackend->pcon);
1579 	xcb_damage_create(pbackend->pcon,damage,window,XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
1580 
1581 	//attach to shared memory
1582 	uint textureSize = rect.w*rect.h*4;
1583 	shmid = shmget(IPC_PRIVATE,(textureSize-1)+pcomp->physicalDevExternalMemoryHostProps.minImportedHostPointerAlignment-(textureSize-1)%pcomp->physicalDevExternalMemoryHostProps.minImportedHostPointerAlignment,IPC_CREAT|0777);
1584 	if(shmid == -1){
1585 		DebugPrintf(stderr,"Failed to allocate shared memory.\n");
1586 		return;
1587 	}
1588 	segment = xcb_generate_id(pbackend->pcon);
1589 	xcb_shm_attach(pbackend->pcon,segment,shmid,0);
1590 	pchpixels = (unsigned char*)shmat(shmid,0,0);
1591 
1592 	xcb_flush(pbackend->pcon);
1593 
1594 	//get image depth
1595 	xcb_shm_get_image_cookie_t imageCookie = xcb_shm_get_image(pbackend->pcon,windowPixmap,0,0,1,1,~0u,XCB_IMAGE_FORMAT_Z_PIXMAP,segment,0);
1596 	xcb_shm_get_image_reply_t *pimageReply = xcb_shm_get_image_reply(pbackend->pcon,imageCookie,0);
1597 
1598 	uint depth;
1599 	if(pimageReply){
1600 		depth = pimageReply->depth;
1601 		free(pimageReply);
1602 	}else{
1603 		DebugPrintf(stderr,"Failed to get SHM image. Assuming 24 bit depth.\n");
1604 		depth = 24;
1605 	}
1606 
1607 	CreateSurface(rect.w,rect.h,depth);
1608 
1609 	if(pcomp->hostMemoryImport && !ptexture->Attach(pchpixels)){
1610 		DebugPrintf(stderr,"Failed to import host memory. Disabling feature.\n");
1611 		pcomp->hostMemoryImport = false;
1612 	}
1613 
1614 	pcomp->AddDamageRegion(this);
1615 	enabled = true;
1616 }
1617 
Unredirect1()1618 void X11ClientFrame::Unredirect1(){
1619 	//
1620 	xcb_composite_unredirect_window(pbackend->pcon,window,XCB_COMPOSITE_REDIRECT_MANUAL);
1621 }
1622 
StopComposition1()1623 void X11ClientFrame::StopComposition1(){
1624 	if(!enabled)
1625 		return;
1626 	if(pcomp->hostMemoryImport)
1627 		ptexture->Detach(pcomp->frameTag);
1628 
1629 	xcb_shm_detach(pbackend->pcon,segment);
1630 	shmdt(pchpixels);
1631 
1632 	shmctl(shmid,IPC_RMID,0);
1633 
1634 	xcb_damage_destroy(pbackend->pcon,damage);
1635 
1636 	xcb_free_pixmap(pbackend->pcon,windowPixmap);
1637 
1638 	DestroySurface();
1639 
1640 	pcomp->AddDamageRegion(this);
1641 	enabled = false;
1642 }
1643 
SetTitle1(const char * ptitle)1644 void X11ClientFrame::SetTitle1(const char *ptitle){
1645 	SetTitle(ptitle);
1646 
1647 	VkRect2D rect;
1648 	rect.offset = {titleRect.x,titleRect.y};
1649 	rect.extent = {titleRect.w,titleRect.h};
1650 	pcomp->AddDamageRegion(&rect);
1651 }
1652 
X11Background(xcb_pixmap_t _pixmap,uint _w,uint _h,const char * _pshaderName[Pipeline::SHADER_MODULE_COUNT],X11Compositor * _pcomp)1653 X11Background::X11Background(xcb_pixmap_t _pixmap, uint _w, uint _h, const char *_pshaderName[Pipeline::SHADER_MODULE_COUNT], X11Compositor *_pcomp) : w(_w), h(_h), ClientFrame(_pshaderName,_pcomp), pcomp11(_pcomp), pixmap(_pixmap){
1654 	//
1655 	uint textureSize = w*h*4;
1656 	shmid = shmget(IPC_PRIVATE,(textureSize-1)+pcomp->physicalDevExternalMemoryHostProps.minImportedHostPointerAlignment-(textureSize-1)%pcomp->physicalDevExternalMemoryHostProps.minImportedHostPointerAlignment,IPC_CREAT|0777);
1657 	if(shmid == -1){
1658 		DebugPrintf(stderr,"Failed to allocate shared memory.\n");
1659 		return;
1660 	}
1661 	segment = xcb_generate_id(pcomp11->pbackend->pcon);
1662 	xcb_shm_attach(pcomp11->pbackend->pcon,segment,shmid,0);
1663 
1664 	pchpixels = (unsigned char*)shmat(shmid,0,0);
1665 
1666 	CreateSurface(w,h,24);
1667 
1668 	if(pcomp->hostMemoryImport && !ptexture->Attach(pchpixels)){
1669 		DebugPrintf(stderr,"Failed to import host memory. Disabling feature.\n");
1670 		pcomp->hostMemoryImport = false;
1671 	}
1672 
1673 	VkRect2D screenRect;
1674 	screenRect.offset = {0,0};
1675 	screenRect.extent = {w,h};
1676 	pcomp->AddDamageRegion(&screenRect);
1677 }
1678 
~X11Background()1679 X11Background::~X11Background(){
1680 	if(pcomp->hostMemoryImport)
1681 		ptexture->Detach(pcomp->frameTag);
1682 
1683 	xcb_shm_detach(pcomp11->pbackend->pcon,segment);
1684 	shmdt(pchpixels);
1685 
1686 	shmctl(shmid,IPC_RMID,0);
1687 
1688 	VkRect2D screenRect;
1689 	screenRect.offset = {0,0};
1690 	screenRect.extent = {w,h};
1691 	pcomp->AddDamageRegion(&screenRect);
1692 }
1693 
UpdateContents(const VkCommandBuffer * pcommandBuffer)1694 void X11Background::UpdateContents(const VkCommandBuffer *pcommandBuffer){
1695 	if(!fullRegionUpdate)
1696 		return;
1697 
1698 	xcb_shm_get_image_cookie_t imageCookie = xcb_shm_get_image(pcomp11->pbackend->pcon,pixmap,0,0,w,h,~0u,XCB_IMAGE_FORMAT_Z_PIXMAP,segment,0);
1699 
1700 	xcb_shm_get_image_reply_t *pimageReply = xcb_shm_get_image_reply(pcomp11->pbackend->pcon,imageCookie,0);
1701 	xcb_flush(pcomp11->pbackend->pcon);
1702 
1703 	if(!pimageReply){
1704 		DebugPrintf(stderr,"No shared memory.\n");
1705 		return;
1706 	}
1707 
1708 	free(pimageReply);
1709 
1710 	VkRect2D screenRect;
1711 	screenRect.offset = {0,0};
1712 	screenRect.extent = {w,h};
1713 
1714 	if(!pcomp->hostMemoryImport){
1715 		unsigned char *pdata = (unsigned char*)ptexture->Map();
1716 		memcpy(pdata,pchpixels,w*h*4);
1717 
1718 		ptexture->Unmap(pcommandBuffer,&screenRect,1);
1719 
1720 	}else{
1721 		ptexture->Update(pcommandBuffer,&screenRect,1);
1722 	}
1723 
1724 	fullRegionUpdate = false;
1725 
1726 	pcomp->AddDamageRegion(&screenRect);
1727 }
1728 
X11Compositor(const Configuration * _pconfig,const Backend::X11Backend * _pbackend)1729 X11Compositor::X11Compositor(const Configuration *_pconfig, const Backend::X11Backend *_pbackend) : CompositorInterface(_pconfig), pbackend(_pbackend){
1730 	//
1731 }
1732 
~X11Compositor()1733 X11Compositor::~X11Compositor(){
1734 	//
1735 }
1736 
Start()1737 void X11Compositor::Start(){
1738 	//compositor
1739 	if(!pbackend->QueryExtension("Composite",&compEventOffset,&compErrorOffset))
1740 		throw Exception("XCompositor unavailable.");
1741 	xcb_composite_query_version_cookie_t compCookie = xcb_composite_query_version(pbackend->pcon,XCB_COMPOSITE_MAJOR_VERSION,XCB_COMPOSITE_MINOR_VERSION);
1742 	xcb_composite_query_version_reply_t *pcompReply = xcb_composite_query_version_reply(pbackend->pcon,compCookie,0);
1743 	if(!pcompReply)
1744 		throw Exception("XCompositor unavailable.");
1745 	DebugPrintf(stdout,"XComposite %u.%u\n",pcompReply->major_version,pcompReply->minor_version);
1746 	free(pcompReply);
1747 
1748 	//overlay
1749 	xcb_composite_get_overlay_window_cookie_t overlayCookie = xcb_composite_get_overlay_window(pbackend->pcon,pbackend->pscr->root);
1750 	xcb_composite_get_overlay_window_reply_t *poverlayReply = xcb_composite_get_overlay_window_reply(pbackend->pcon,overlayCookie,0);
1751 	if(!poverlayReply)
1752 		throw Exception("Unable to get overlay window.");
1753 	overlay = poverlayReply->overlay_win;
1754 	free(poverlayReply);
1755 	DebugPrintf(stdout,"overlay xid: %u\n",overlay);
1756 
1757 	uint mask = XCB_CW_EVENT_MASK;
1758 	uint values[1] = {XCB_EVENT_MASK_EXPOSURE};
1759 	xcb_change_window_attributes(pbackend->pcon,overlay,mask,values);
1760 
1761 	//xfixes
1762 	if(!pbackend->QueryExtension("XFIXES",&xfixesEventOffset,&xfixesErrorOffset))
1763 		throw Exception("XFixes unavailable.");
1764 	xcb_xfixes_query_version_cookie_t fixesCookie = xcb_xfixes_query_version(pbackend->pcon,XCB_XFIXES_MAJOR_VERSION,XCB_XFIXES_MINOR_VERSION);
1765 	xcb_xfixes_query_version_reply_t *pfixesReply = xcb_xfixes_query_version_reply(pbackend->pcon,fixesCookie,0);
1766 	if(!pfixesReply)
1767 		throw Exception("XFixes unavailable.");
1768 	DebugPrintf(stdout,"XFixes %u.%u\n",pfixesReply->major_version,pfixesReply->minor_version);
1769 	free(pfixesReply);
1770 
1771 	//allow overlay input passthrough
1772 	xcb_xfixes_region_t region = xcb_generate_id(pbackend->pcon);
1773 	xcb_void_cookie_t regionCookie = xcb_xfixes_create_region_checked(pbackend->pcon,region,0,0);
1774 	xcb_generic_error_t *perr = xcb_request_check(pbackend->pcon,regionCookie);
1775 	if(perr != 0){
1776 		snprintf(Exception::buffer,sizeof(Exception::buffer),"Unable to create overlay region (%d).",perr->error_code);
1777 		throw Exception();
1778 	}
1779 	xcb_discard_reply(pbackend->pcon,regionCookie.sequence);
1780 	xcb_xfixes_set_window_shape_region(pbackend->pcon,overlay,XCB_SHAPE_SK_BOUNDING,0,0,XCB_XFIXES_REGION_NONE);
1781 	xcb_xfixes_set_window_shape_region(pbackend->pcon,overlay,XCB_SHAPE_SK_INPUT,0,0,region);
1782 	xcb_xfixes_destroy_region(pbackend->pcon,region);
1783 
1784 	//damage
1785 	if(!pbackend->QueryExtension("DAMAGE",&damageEventOffset,&damageErrorOffset))
1786 		throw Exception("Damage extension unavailable.");
1787 
1788 	xcb_damage_query_version_cookie_t damageCookie = xcb_damage_query_version(pbackend->pcon,XCB_DAMAGE_MAJOR_VERSION,XCB_DAMAGE_MINOR_VERSION);
1789 	xcb_damage_query_version_reply_t *pdamageReply = xcb_damage_query_version_reply(pbackend->pcon,damageCookie,0);
1790 	if(!pdamageReply)
1791 		throw Exception("Damage extension unavailable.");
1792 	DebugPrintf(stdout,"Damage %u.%u\n",pdamageReply->major_version,pdamageReply->minor_version);
1793 	free(pdamageReply);
1794 
1795 	xcb_shm_query_version_cookie_t shmCookie = xcb_shm_query_version(pbackend->pcon);
1796 	xcb_shm_query_version_reply_t *pshmReply = xcb_shm_query_version_reply(pbackend->pcon,shmCookie,0);
1797 	if(!pshmReply || !pshmReply->shared_pixmaps)
1798 		throw Exception("SHM extension unavailable.");
1799 	DebugPrintf(stdout,"SHM %u.%u\n",pshmReply->major_version,pshmReply->minor_version);
1800 	free(pshmReply);
1801 
1802 	xcb_dri3_query_version_cookie_t dri3Cookie = xcb_dri3_query_version(pbackend->pcon,XCB_DRI3_MAJOR_VERSION,XCB_DRI3_MINOR_VERSION);
1803 	xcb_dri3_query_version_reply_t *pdri3Reply = xcb_dri3_query_version_reply(pbackend->pcon,dri3Cookie,0);
1804 	if(!pdri3Reply)
1805 		throw Exception("DRI3 extension unavailable.");
1806 	DebugPrintf(stdout,"DRI3 %u.%u\n",pdri3Reply->major_version,pdri3Reply->minor_version);
1807 	free(pdri3Reply);
1808 
1809 	xcb_flush(pbackend->pcon);
1810 
1811 	InitializeRenderEngine();
1812 
1813 	/*char cardStr[256];
1814 	snprintf(cardStr,sizeof(cardStr),"/dev/dri/card%u",physicalDevIndex);
1815 
1816 	cardfd = open(cardStr,O_RDWR|FD_CLOEXEC);
1817 	if(cardfd < 0){
1818 		snprintf(Exception::buffer,sizeof(Exception::buffer),"Failed to open %s",cardStr);
1819 		throw Exception();
1820 	}
1821 	pgbmdev = gbm_create_device(cardfd);
1822 	if(!pgbmdev)
1823 		throw Exception("Failed to create GBM device.");*/
1824 }
1825 
Stop()1826 void X11Compositor::Stop(){
1827 	if(dynamic_cast<ClientFrame *>(pbackground))
1828 		delete pbackground;
1829 	if(pcolorBackground)
1830 		delete pcolorBackground;
1831 	DestroyRenderEngine();
1832 
1833 	/*gbm_device_destroy(pgbmdev);
1834 	close(cardfd);*/
1835 
1836 	xcb_xfixes_set_window_shape_region(pbackend->pcon,overlay,XCB_SHAPE_SK_BOUNDING,0,0,XCB_XFIXES_REGION_NONE);
1837 	xcb_xfixes_set_window_shape_region(pbackend->pcon,overlay,XCB_SHAPE_SK_INPUT,0,0,XCB_XFIXES_REGION_NONE);
1838 
1839 	xcb_composite_release_overlay_window(pbackend->pcon,overlay);
1840 
1841 	xcb_flush(pbackend->pcon);
1842 }
1843 
Resume()1844 void X11Compositor::Resume(){
1845 	if(!suspended)
1846 		return;
1847 	xcb_map_window(pbackend->pcon,overlay);
1848 	xcb_flush(pbackend->pcon);
1849 	suspended = false;
1850 }
1851 
Suspend()1852 void X11Compositor::Suspend(){
1853 	if(suspended)
1854 		return;
1855 	xcb_unmap_window(pbackend->pcon,overlay);
1856 	xcb_flush(pbackend->pcon);
1857 	suspended = true;
1858 }
1859 
FilterEvent(const Backend::X11Event * pevent)1860 bool X11Compositor::FilterEvent(const Backend::X11Event *pevent){
1861 	if(pevent->pevent->response_type == XCB_DAMAGE_NOTIFY+damageEventOffset){
1862 		xcb_damage_notify_event_t *pev = (xcb_damage_notify_event_t*)pevent->pevent;
1863 
1864 		Backend::X11Client *pclient = pevent->pbackend->FindClient(pev->drawable,Backend::X11Backend::MODE_UNDEFINED);
1865 		if(!pclient){
1866 			DebugPrintf(stderr,"Unknown damage event.\n");
1867 			return true;
1868 		}
1869 
1870 		X11ClientFrame *pclientFrame = dynamic_cast<X11ClientFrame *>(pclient);
1871 
1872 		xcb_xfixes_region_t region = xcb_generate_id(pbackend->pcon);
1873 		xcb_xfixes_create_region(pbackend->pcon,region,0,0);
1874 		xcb_damage_subtract(pbackend->pcon,pclientFrame->damage,0,region);
1875 
1876 		xcb_xfixes_fetch_region_cookie_t fetchRegionCookie = xcb_xfixes_fetch_region_unchecked(pbackend->pcon,region);
1877 		xcb_xfixes_destroy_region(pbackend->pcon,region);
1878 
1879 		xcb_xfixes_fetch_region_reply_t *pfetchRegionReply = xcb_xfixes_fetch_region_reply(pbackend->pcon,fetchRegionCookie,0);
1880 
1881 		if(!pfetchRegionReply || !pclientFrame->enabled){
1882 			free(pfetchRegionReply);
1883 			return true;
1884 		}
1885 
1886 		uint count = xcb_xfixes_fetch_region_rectangles_length(pfetchRegionReply);
1887 		if(count > 0){
1888 			xcb_rectangle_t *prects = xcb_xfixes_fetch_region_rectangles(pfetchRegionReply);
1889 			for(uint i = 0; i < count; ++i){
1890 				if(pclient->rect.w >= prects[i].x+prects[i].width && pclient->rect.h >= prects[i].y+prects[i].height){
1891 					VkRect2D rect;
1892 					rect.offset = {prects[i].x,prects[i].y};
1893 					rect.extent = {prects[i].width,prects[i].height};
1894 					pclientFrame->damageRegions.push_back(rect);
1895 				}
1896 			}
1897 		}else{
1898 			if(pclient->rect.w >= pev->area.x+pev->area.width && pclient->rect.h >= pev->area.y+pev->area.height){
1899 				VkRect2D rect;
1900 				rect.offset = {pfetchRegionReply->extents.x,pfetchRegionReply->extents.y};
1901 				rect.extent = {pfetchRegionReply->extents.width,pfetchRegionReply->extents.height};
1902 				pclientFrame->damageRegions.push_back(rect);
1903 			}
1904 		}
1905 
1906 		free(pfetchRegionReply);
1907 
1908 		/*if(pclient->rect.w < pev->area.x+pev->area.width || pclient->rect.h < pev->area.y+pev->area.height)
1909 			return true; //filter out outdated events after client shrink in size*/
1910 
1911 		if(std::find(updateQueue.begin(),updateQueue.end(),pclientFrame) == updateQueue.end())
1912 			updateQueue.push_back(pclientFrame);
1913 
1914 		/*VkRect2D rect;
1915 		rect.offset = {pev->area.x,pev->area.y};
1916 		rect.extent = {pev->area.width,pev->area.height};
1917 		pclientFrame->damageRegions.push_back(rect);
1918 		//DebugPrintf(stdout,"DAMAGE_EVENT, %x, (%hd,%hd), (%hux%hu)\n",pev->drawable,pev->area.x,pev->area.y,pev->area.width,pev->area.height);*/
1919 
1920 		return true;
1921 	}
1922 
1923 	return false;
1924 }
1925 
CheckPresentQueueCompatibility(VkPhysicalDevice physicalDev,uint queueFamilyIndex) const1926 bool X11Compositor::CheckPresentQueueCompatibility(VkPhysicalDevice physicalDev, uint queueFamilyIndex) const{
1927 	xcb_visualid_t visualid = pbackend->pscr->root_visual;
1928 	return vkGetPhysicalDeviceXcbPresentationSupportKHR(physicalDev,queueFamilyIndex,pbackend->pcon,visualid) == VK_TRUE;
1929 }
1930 
CreateSurfaceKHR(VkSurfaceKHR * psurface) const1931 void X11Compositor::CreateSurfaceKHR(VkSurfaceKHR *psurface) const{
1932 	VkXcbSurfaceCreateInfoKHR xcbSurfaceCreateInfo = {};
1933 	xcbSurfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
1934 	xcbSurfaceCreateInfo.pNext = 0;
1935 	xcbSurfaceCreateInfo.connection = pbackend->pcon; //pcon
1936 	xcbSurfaceCreateInfo.window = overlay;
1937 	if(vkCreateXcbSurfaceKHR(instance,&xcbSurfaceCreateInfo,0,psurface) != VK_SUCCESS)
1938 		throw("Failed to create KHR surface.");
1939 }
1940 
SetBackgroundPixmap(const Backend::BackendPixmapProperty * pPixmapProperty)1941 void X11Compositor::SetBackgroundPixmap(const Backend::BackendPixmapProperty *pPixmapProperty){
1942 	if(pbackground){
1943 		delete pbackground;
1944 		pbackground = pcolorBackground;
1945 	}
1946 	if(pPixmapProperty->pixmap != 0){
1947 		xcb_get_geometry_cookie_t geometryCookie = xcb_get_geometry(pbackend->pcon,pPixmapProperty->pixmap);
1948 		xcb_get_geometry_reply_t *pgeometryReply = xcb_get_geometry_reply(pbackend->pcon,geometryCookie,0);
1949 		if(!pgeometryReply)
1950 			throw("Invalid geometry size - unable to retrieve.");
1951 
1952 		static const char *pshaderName[Pipeline::SHADER_MODULE_COUNT] = {
1953 			"default_vertex.spv","default_geometry.spv","default_fragment.spv"
1954 		};
1955 		pbackground = new X11Background(pPixmapProperty->pixmap,pgeometryReply->width,pgeometryReply->height,pshaderName,this);
1956 		printf("background set!\n");
1957 	}
1958 }
1959 
GetExtent() const1960 VkExtent2D X11Compositor::GetExtent() const{
1961 	xcb_get_geometry_cookie_t geometryCookie = xcb_get_geometry(pbackend->pcon,overlay);
1962 	xcb_get_geometry_reply_t *pgeometryReply = xcb_get_geometry_reply(pbackend->pcon,geometryCookie,0);
1963 	if(!pgeometryReply)
1964 		throw("Invalid geometry size - unable to retrieve.");
1965 	VkExtent2D e = (VkExtent2D){pgeometryReply->width,pgeometryReply->height};
1966 	free(pgeometryReply);
1967 	return e;
1968 }
1969 
GetDPI() const1970 glm::vec2 X11Compositor::GetDPI() const{
1971 	return glm::vec2(25.4f*(float)pbackend->pscr->width_in_pixels/(float)pbackend->pscr->width_in_millimeters,25.4f*(float)pbackend->pscr->height_in_pixels/(float)pbackend->pscr->height_in_millimeters);
1972 }
1973 
X11DebugClientFrame(Backend::DebugContainer * pcontainer,const Backend::DebugClient::CreateInfo * _pcreateInfo,const char * _pshaderName[Pipeline::SHADER_MODULE_COUNT],CompositorInterface * _pcomp)1974 X11DebugClientFrame::X11DebugClientFrame(Backend::DebugContainer *pcontainer, const Backend::DebugClient::CreateInfo *_pcreateInfo, const char *_pshaderName[Pipeline::SHADER_MODULE_COUNT], CompositorInterface *_pcomp) : DebugClient(pcontainer,_pcreateInfo), ClientFrame(_pshaderName,_pcomp){
1975 	//
1976 	StartComposition1();
1977 }
1978 
~X11DebugClientFrame()1979 X11DebugClientFrame::~X11DebugClientFrame(){
1980 	StopComposition1();
1981 }
1982 
UpdateContents(const VkCommandBuffer * pcommandBuffer)1983 void X11DebugClientFrame::UpdateContents(const VkCommandBuffer *pcommandBuffer){
1984 	//
1985 	uint color[3];
1986 	for(uint &t : color)
1987 		t = rand()%190;
1988 	unsigned char *pdata = (unsigned char*)ptexture->Map();
1989 	for(uint i = 0, n = rect.w*rect.h; i < n; ++i){
1990 		//unsigned char t = (float)(i/rect.w)/(float)rect.h*255;
1991 		pdata[4*i+0] = color[0];
1992 		pdata[4*i+1] = color[1];
1993 		pdata[4*i+2] = color[2];
1994 		pdata[4*i+3] = 190;//255;
1995 	}
1996 	VkRect2D rect1;
1997 	rect1.offset = {0,0};
1998 	rect1.extent = {rect.w,rect.h};
1999 	ptexture->Unmap(pcommandBuffer,&rect1,1);
2000 
2001 	pcomp->AddDamageRegion(&rect1);
2002 }
2003 
AdjustSurface1()2004 void X11DebugClientFrame::AdjustSurface1(){
2005 	if(oldRect.w != rect.w || oldRect.h != rect.h){
2006 		AdjustSurface(rect.w,rect.h);
2007 		pcomp->AddDamageRegion(this);
2008 	}else
2009 	if(oldRect.x != rect.x || oldRect.y != rect.y)
2010 		pcomp->AddDamageRegion(this);
2011 }
2012 
Redirect1()2013 void X11DebugClientFrame::Redirect1(){
2014 	//
2015 }
2016 
StartComposition1()2017 void X11DebugClientFrame::StartComposition1(){
2018 	if(enabled)
2019 		return;
2020 	CreateSurface(rect.w,rect.h,32);
2021 	pcomp->AddDamageRegion(this);
2022 	enabled = true;
2023 }
2024 
Unredirect1()2025 void X11DebugClientFrame::Unredirect1(){
2026 	//
2027 }
2028 
StopComposition1()2029 void X11DebugClientFrame::StopComposition1(){
2030 	if(!enabled)
2031 		return;
2032 	DestroySurface();
2033 	pcomp->AddDamageRegion(this);
2034 	enabled = false;
2035 }
2036 
SetTitle1(const char * ptitle)2037 void X11DebugClientFrame::SetTitle1(const char *ptitle){
2038 	SetTitle(ptitle);
2039 
2040 	VkRect2D rect;
2041 	rect.offset = {titleRect.x,titleRect.y};
2042 	rect.extent = {titleRect.w,titleRect.h};
2043 	pcomp->AddDamageRegion(&rect);
2044 }
2045 
X11DebugCompositor(const Configuration * _pconfig,const Backend::X11Backend * pbackend)2046 X11DebugCompositor::X11DebugCompositor(const Configuration *_pconfig, const Backend::X11Backend *pbackend) : X11Compositor(_pconfig,pbackend){
2047 	//
2048 }
2049 
~X11DebugCompositor()2050 X11DebugCompositor::~X11DebugCompositor(){
2051 	//
2052 }
2053 
Start()2054 void X11DebugCompositor::Start(){
2055 	overlay = pbackend->window;
2056 
2057 	InitializeRenderEngine();
2058 }
2059 
Stop()2060 void X11DebugCompositor::Stop(){
2061 	DestroyRenderEngine();
2062 }
2063 
Resume()2064 void X11DebugCompositor::Resume(){
2065 	//
2066 }
2067 
Suspend()2068 void X11DebugCompositor::Suspend(){
2069 	//
2070 }
2071 
NullCompositor()2072 NullCompositor::NullCompositor() : CompositorInterface(&config){
2073 	//
2074 }
2075 
~NullCompositor()2076 NullCompositor::~NullCompositor(){
2077 	//
2078 }
2079 
Start()2080 void NullCompositor::Start(){
2081 	//
2082 }
2083 
Stop()2084 void NullCompositor::Stop(){
2085 	//
2086 }
2087 
Resume()2088 void NullCompositor::Resume(){
2089 	//
2090 }
2091 
Suspend()2092 void NullCompositor::Suspend(){
2093 	//
2094 }
CheckPresentQueueCompatibility(VkPhysicalDevice physicalDev,uint queueFamilyIndex) const2095 bool NullCompositor::CheckPresentQueueCompatibility(VkPhysicalDevice physicalDev, uint queueFamilyIndex) const{
2096 	return true;
2097 }
2098 
CreateSurfaceKHR(VkSurfaceKHR * psurface) const2099 void NullCompositor::CreateSurfaceKHR(VkSurfaceKHR *psurface) const{
2100 	//
2101 }
2102 
GetExtent() const2103 VkExtent2D NullCompositor::GetExtent() const{
2104 	return (VkExtent2D){0,0};
2105 }
2106 
GetDPI() const2107 glm::vec2 NullCompositor::GetDPI() const{
2108 	return glm::vec2(0.0f);
2109 }
2110 
2111 }
2112 
2113