1 #ifndef COMPOSITOR_H
2 #define COMPOSITOR_H
3 
4 #include <vulkan/vulkan.h>
5 #include <vulkan/vulkan_xcb.h>
6 
7 #include <xcb/composite.h>
8 #include <xcb/damage.h>
9 #include <xcb/shm.h>
10 #include <xcb/dri3.h>
11 
12 #include <string>
13 
14 //struct gbm_device;
15 
16 namespace Backend{
17 class X11Backend;
18 };
19 
20 namespace Compositor{
21 
22 class Drawable{
23 friend class CompositorInterface;
24 public:
25 	Drawable(Pipeline *, CompositorInterface *);
26 	virtual ~Drawable();
27 	//
28 	bool AssignPipeline(const Pipeline *);
29 protected:
30 	void BindShaderResources(const std::vector<std::pair<ShaderModule::VARIABLE, const void *>> *, const VkCommandBuffer *);
UpdateDescSets()31 	virtual void UpdateDescSets(){};
32 	class CompositorInterface *pcomp;
33 	struct PipelineDescriptorSet{
34 		uint64 fenceTag;
35 		const Pipeline *p;
36 		VkDescriptorSet *pdescSets[Pipeline::SHADER_MODULE_COUNT];
37 	};
38 	PipelineDescriptorSet *passignedSet;
39 	std::vector<PipelineDescriptorSet> descSets;
40 };
41 
42 class ColorFrame : public Drawable{
43 friend class CompositorInterface;
44 public:
45 	ColorFrame(const char *[Pipeline::SHADER_MODULE_COUNT], class CompositorInterface *);
46 	virtual ~ColorFrame();
47 	void Draw(const VkRect2D &, const glm::vec2 &, const glm::vec2 &, const glm::vec2 &, uint, uint, const VkCommandBuffer *);
48 protected:
49 	struct timespec creationTime;
50 	float time;
51 public:
52 	uint shaderUserFlags;
53 protected:
54 	uint shaderFlags; //current frame shader flags
55 	uint oldShaderFlags; //used to keep track of changes
56 };
57 
58 class ClientFrame : public ColorFrame{
59 friend class CompositorInterface;
60 friend class X11Compositor;
61 public:
62 	ClientFrame(const char *[Pipeline::SHADER_MODULE_COUNT], class CompositorInterface *);
63 	virtual ~ClientFrame();
64 	virtual void UpdateContents(const VkCommandBuffer *) = 0;
65 	virtual void Exclude(bool);
66 	void CreateSurface(uint, uint, uint);
67 	void AdjustSurface(uint, uint);
68 	void DestroySurface();
69 	void SetShaders(const char *[Pipeline::SHADER_MODULE_COUNT]);
70 	void SetTitle(const char *);
71 	enum SHADER_FLAG{ //+config
72 		SHADER_FLAG_FOCUS = 0x1,
73 		SHADER_FLAG_FLOATING = 0x2,
74 		SHADER_FLAG_STACKED = 0x4,
75 		SHADER_FLAG_USER_BIT = 0x8
76 	};
77 protected:
78 	void UpdateDescSets();
79 	Texture *ptexture;
80 	class Text *ptitle;
81 	std::string title;
82 	uint surfaceDepth;
83 public:
84 	bool enabled; //in use and ready to draw
85 protected:
86 	bool fullRegionUpdate;
87 	bool animationCompleted;
88 };
89 
90 class CompositorInterface{
91 friend class TextureBase;
92 friend class TextureStaged;
93 friend class TexturePixmap;
94 friend class TextureHostPointer;
95 friend class Texture;
96 friend class Buffer;
97 friend class ShaderModule;
98 friend class Pipeline;
99 friend class ClientPipeline;
100 friend class FontAtlas;
101 friend class Text;
102 friend class TextEngine;
103 friend class Drawable;
104 friend class ColorFrame;
105 friend class ClientFrame;
106 friend class X11ClientFrame;
107 friend class X11Background;
108 friend class X11DebugClientFrame;
109 public:
110 	struct Configuration{
111 		uint deviceIndex;
112 		bool debugLayers;
113 		bool scissoring;
114 		bool hostMemoryImport;
115 		bool unredirOnFullscreen;
116 		bool enableAnimation;
117 		float animationDuration;
118 		const char *pfontName;
119 		uint fontSize;
120 	};
121 	CompositorInterface(const Configuration *);
122 	virtual ~CompositorInterface();
123 	virtual void Start() = 0; //initialize and start for the first time
124 	virtual void Stop() = 0; //stop and cleanup
125 	virtual void Resume() = 0; //resume after suspension
126 	virtual void Suspend() = 0; //suspend (unredirection, for example)
127 protected:
128 	void InitializeRenderEngine();
129 	void InitializeSwapchain();
130 	void DestroyRenderEngine();
131 	void DestroySwapchain();
132 	void AddShader(const char *, const Blob *);
133 	void AddDamageRegion(const VkRect2D *);
134 	void AddDamageRegion(const WManager::Client *);
135 	void WaitIdle();
136 	void CreateRenderQueueAppendix(const WManager::Client *, const WManager::Container *);
137 	void CreateRenderQueue(const WManager::Container *, const WManager::Container *);
138 	bool PollFrameFence(bool);
139 	void GenerateCommandBuffers(const WManager::Container *, const std::vector<std::pair<const WManager::Client *, WManager::Client *>> *, const WManager::Container *);
140 	void Present();
141 	virtual bool CheckPresentQueueCompatibility(VkPhysicalDevice, uint) const = 0;
142 	virtual void CreateSurfaceKHR(VkSurfaceKHR *) const = 0;
143 	virtual VkExtent2D GetExtent() const = 0;
144 	virtual glm::vec2 GetDPI() const = 0;
145 	VkInstance instance;
146 	VkSurfaceCapabilitiesKHR surfaceCapabilities;
147 	VkSurfaceKHR surface;
148 	VkDebugReportCallbackEXT debugReportCb;
149 	VkPhysicalDevice physicalDev;
150 	VkPhysicalDeviceProperties physicalDevProps;
151 	VkPhysicalDeviceExternalMemoryHostPropertiesEXT physicalDevExternalMemoryHostProps;
152 	VkDevice logicalDev;
153 	enum QUEUE_INDEX{
154 		QUEUE_INDEX_GRAPHICS,
155 		QUEUE_INDEX_PRESENT,
156 		//QUEUE_INDEX_TRANSFER,
157 		QUEUE_INDEX_COUNT
158 	};
159 	VkQueue queue[QUEUE_INDEX_COUNT];
160 	VkRenderPass renderPass;
161 	VkSwapchainKHR swapChain;
162 	VkExtent2D imageExtent;
163 	VkImage *pswapChainImages;
164 	VkImageView *pswapChainImageViews;
165 	VkFramebuffer *pframebuffers;
166 	enum SEMAPHORE_INDEX{
167 		SEMAPHORE_INDEX_IMAGE_AVAILABLE,
168 		SEMAPHORE_INDEX_RENDER_FINISHED,
169 		SEMAPHORE_INDEX_COUNT
170 	};
171 	VkSemaphore (*psemaphore)[SEMAPHORE_INDEX_COUNT];
172 	VkFence *pfence;
173 	//back buffer to enable the use of previous frame contents
174 	//VkImage renderImage;
175 	//VkDeviceMemory renderImageDeviceMemory;
176 
177 	VkCommandPool commandPool;
178 	VkCommandBuffer *pcommandBuffers;
179 	VkCommandBuffer *pcopyCommandBuffers;
180 
181 	//VkDescriptorPool descPool;
182 	std::deque<VkDescriptorPool> descPoolArray;
183 	std::vector<std::pair<VkDescriptorSet *, VkDescriptorPool>> descPoolReference;
184 
185 	uint queueFamilyIndex[QUEUE_INDEX_COUNT]; //
186 	uint physicalDevIndex;
187 	uint swapChainImageCount;
188 	uint currentFrame;
189 	uint imageIndex;
190 
191 	template<class T>
192 	Pipeline * LoadPipeline(const char *[Pipeline::SHADER_MODULE_COUNT], const std::vector<std::pair<ShaderModule::INPUT,uint>> *);
193 
194 	std::vector<ShaderModule> shaders;
195 	std::vector<std::pair<size_t, Pipeline *>> pipelines; //hash, pipeline
196 
197 	std::vector<ClientFrame *> updateQueue;
198 	std::vector<ClientFrame *> titleUpdateQueue;
199 	//Scissoring regions based on client damage. Second (uint) is a bitmask for
200 	//swap chain images, indicating which image has been updated so far. When
201 	//all images have been updated, the region is removed from the list.
202 	std::vector<std::pair<VkRect2D, uint>> scissorRegions;
203 	std::vector<VkRectLayerKHR> presentRectLayers;
204 
205 	void ClearBackground();
206 
207 	ColorFrame *pcolorBackground;
208 	ColorFrame *pbackground;
209 public:
210 	class TextEngine *ptextEngine;
211 	const char *pfontName;
212 	uint fontSize;
213 protected:
214 
215 	VkSampler pointSampler;
216 
217 	struct timespec frameTime;
218 	uint64 frameTag; //frame counter, to prevent releasing resources still in use
219 
220 	struct RenderObject{
221 		WManager::Client *pclient;
222 		ClientFrame *pclientFrame;
223 		//uint flags;
224 	};
225 	std::vector<RenderObject> renderQueue;
226 
227 	typedef std::tuple<const WManager::Client *, WManager::Client *, ClientFrame *> AppendixQueueElement;
228 	std::deque<AppendixQueueElement> appendixQueue;
229 
230 	//Used textures get stored for potential reuse before they get destroyed and while waiting for the pipeline to get flushed.
231 	//Many of the allocated window textures will initially have some common reoccuring size.
232 	Texture * CreateTexture(uint, uint, uint);
233 	void ReleaseTexture(Texture *);
234 
235 	struct TextureCacheEntry{
236 		Texture *ptexture;
237 		uint64 releaseTag;
238 		struct timespec releaseTime;
239 	};
240 	std::vector<TextureCacheEntry> textureCache;
241 
242 	VkDescriptorSet * CreateDescSets(const ShaderModule *);
243 	void ReleaseDescSets(const ShaderModule *, VkDescriptorSet *);
244 
245 	struct DescSetCacheEntry{
246 		VkDescriptorSet *pdescSets;
247 		uint setCount;
248 		uint64 releaseTag;
249 	};
250 	std::vector<DescSetCacheEntry> descSetCache;
251 
252 	ClientFrame *pfsApp; //fullscreen state app for the current frame (for unredirection)
253 	ClientFrame *pfsAppPrev; //fullscreen state app during previous frame (for unredirection)
254 	bool frameApproval;
255 	bool suspended; //entire compositor is suspended - all windows are unredirected
256 	bool unredirected; //one of the applications is underirected due to it being fullscreen
257 	bool playingAnimation;
258 
259 	//config
260 	bool debugLayers;
261 	bool scissoring;
262 	bool hostMemoryImport;
263 	bool unredirOnFullscreen;
264 
265 public:
266 	bool enableAnimation;
267 	float animationDuration;
268 protected:
269 
270 	static VKAPI_ATTR VkBool32 VKAPI_CALL ValidationLayerDebugCallback(VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *, void *);
271 	static VKAPI_ATTR VkBool32 VKAPI_CALL ValidationLayerDebugCallback2(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *, void *);
272 };
273 
274 class X11ClientFrame : public Backend::X11Client, public ClientFrame{
275 public:
276 	X11ClientFrame(Backend::X11Container *, const Backend::X11Client::CreateInfo *, const char *[Pipeline::SHADER_MODULE_COUNT], CompositorInterface *);
277 	~X11ClientFrame();
278 	void UpdateContents(const VkCommandBuffer *);
279 	void Exclude(bool);
280 	void AdjustSurface1();
281 	void Redirect1();
282 	void StartComposition1();
283 	void Unredirect1();
284 	void StopComposition1();
285 	void SetTitle1(const char *);
286 	xcb_pixmap_t windowPixmap;
287 	xcb_shm_seg_t segment;
288 	xcb_damage_damage_t damage;
289 	std::vector<VkRect2D> damageRegions;
290 	sint shmid;
291 	unsigned char *pchpixels;
292 };
293 
294 class X11Background : public ClientFrame{
295 public:
296 	X11Background(xcb_pixmap_t, uint, uint, const char *[Pipeline::SHADER_MODULE_COUNT], X11Compositor *);
297 	~X11Background();
298 	void UpdateContents(const VkCommandBuffer *);
299 
300 	X11Compositor *pcomp11;
301 	xcb_pixmap_t pixmap;
302 	xcb_shm_seg_t segment;
303 	uint w, h;
304 	sint shmid;
305 	unsigned char *pchpixels;
306 };
307 
308 //Default compositor assumes XCB for its surface
309 class X11Compositor : public CompositorInterface{
310 friend class TexturePixmap;
311 public:
312 	//Derivatives of compositor classes should not point to their default corresponding backend classes (Backend::Default in this case). This is to allow the compositor to be independent of the backend implementation, as long as it's based on X11 here.
313 	X11Compositor(const Configuration *, const Backend::X11Backend *);
314 	~X11Compositor();
315 	virtual void Start();
316 	virtual void Stop();
317 	virtual void Resume();
318 	virtual void Suspend();
319 	bool FilterEvent(const Backend::X11Event *);
320 	bool CheckPresentQueueCompatibility(VkPhysicalDevice, uint) const;
321 	void CreateSurfaceKHR(VkSurfaceKHR *) const;
322 	void SetBackgroundPixmap(const Backend::BackendPixmapProperty *);
323 	VkExtent2D GetExtent() const;
324 	glm::vec2 GetDPI() const;
325 	const Backend::X11Backend *pbackend;
326 	/*struct gbm_device *pgbmdev;
327 	sint cardfd;*/
328 	xcb_window_t overlay;
329 protected:
330 	sint compEventOffset;
331 	sint compErrorOffset;
332 	sint xfixesEventOffset;
333 	sint xfixesErrorOffset;
334 	sint damageEventOffset;
335 	sint damageErrorOffset;
336 };
337 
338 class X11DebugClientFrame : public Backend::DebugClient, public ClientFrame{
339 public:
340 	X11DebugClientFrame(Backend::DebugContainer *, const Backend::DebugClient::CreateInfo *, const char *[Pipeline::SHADER_MODULE_COUNT], CompositorInterface *);
341 	~X11DebugClientFrame();
342 	void UpdateContents(const VkCommandBuffer *);
343 	void AdjustSurface1();
344 	void Redirect1();
345 	void StartComposition1();
346 	void Unredirect1();
347 	void StopComposition1();
348 	void SetTitle1(const char *);
349 };
350 
351 class X11DebugCompositor : public X11Compositor{
352 public:
353 	X11DebugCompositor(const Configuration *, const Backend::X11Backend *);
354 	~X11DebugCompositor();
355 	void Start();
356 	void Stop();
357 	void Resume();
358 	void Suspend();
359 };
360 
361 class NullCompositor : public CompositorInterface{
362 public:
363 	NullCompositor();
364 	~NullCompositor();
365 	void Start();
366 	void Stop();
367 	void Resume();
368 	void Suspend();
369 	bool CheckPresentQueueCompatibility(VkPhysicalDevice, uint) const;
370 	void CreateSurfaceKHR(VkSurfaceKHR *) const;
371 	VkExtent2D GetExtent() const;
372 	glm::vec2 GetDPI() const;
373 	Configuration config{ //dummy config
374 		.deviceIndex = 0,
375 		.debugLayers = false,
376 		.scissoring = true,
377 		.hostMemoryImport = true,
378 		.enableAnimation = false,
379 		.animationDuration = 0.3f,
380 		.pfontName = "Monospace",
381 		.fontSize = 18,
382 	};
383 };
384 
385 }
386 
387 #endif
388 
389