1/*
2 * Copyright © 2016 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include <assert.h>
25#include <stdbool.h>
26
27#include "radv_meta.h"
28#include "radv_private.h"
29#include "nir/nir_builder.h"
30#include "sid.h"
31/**
32 * Vertex attributes used by all pipelines.
33 */
34struct vertex_attrs {
35	float position[2]; /**< 3DPRIM_RECTLIST */
36};
37
38/* passthrough vertex shader */
39static nir_shader *
40build_nir_vs(void)
41{
42	const struct glsl_type *vec4 = glsl_vec4_type();
43
44	nir_builder b;
45	nir_variable *a_position;
46	nir_variable *v_position;
47
48	nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, NULL);
49	b.shader->info->name = ralloc_strdup(b.shader, "meta_fast_clear_vs");
50
51	a_position = nir_variable_create(b.shader, nir_var_shader_in, vec4,
52					 "a_position");
53	a_position->data.location = VERT_ATTRIB_GENERIC0;
54
55	v_position = nir_variable_create(b.shader, nir_var_shader_out, vec4,
56					 "gl_Position");
57	v_position->data.location = VARYING_SLOT_POS;
58
59	nir_copy_var(&b, v_position, a_position);
60
61	return b.shader;
62}
63
64/* simple passthrough shader */
65static nir_shader *
66build_nir_fs(void)
67{
68	nir_builder b;
69
70	nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
71	b.shader->info->name = ralloc_asprintf(b.shader,
72					      "meta_fast_clear_noop_fs");
73
74	return b.shader;
75}
76
77static VkResult
78create_pass(struct radv_device *device)
79{
80	VkResult result;
81	VkDevice device_h = radv_device_to_handle(device);
82	const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
83	VkAttachmentDescription attachment;
84
85	attachment.format = VK_FORMAT_UNDEFINED;
86	attachment.samples = 1;
87	attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
88	attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
89	attachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
90	attachment.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
91
92	result = radv_CreateRenderPass(device_h,
93				       &(VkRenderPassCreateInfo) {
94					       .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
95						       .attachmentCount = 1,
96						       .pAttachments = &attachment,
97						       .subpassCount = 1,
98						       .pSubpasses = &(VkSubpassDescription) {
99						       .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
100						       .inputAttachmentCount = 0,
101						       .colorAttachmentCount = 1,
102						       .pColorAttachments = (VkAttachmentReference[]) {
103							       {
104								       .attachment = 0,
105								       .layout = VK_IMAGE_LAYOUT_GENERAL,
106							       },
107						       },
108						       .pResolveAttachments = NULL,
109						       .pDepthStencilAttachment = &(VkAttachmentReference) {
110							       .attachment = VK_ATTACHMENT_UNUSED,
111						       },
112						       .preserveAttachmentCount = 0,
113						       .pPreserveAttachments = NULL,
114					       },
115								.dependencyCount = 0,
116				       },
117				       alloc,
118				       &device->meta_state.fast_clear_flush.pass);
119
120	return result;
121}
122
123static VkResult
124create_pipeline(struct radv_device *device,
125                VkShaderModule vs_module_h)
126{
127	VkResult result;
128	VkDevice device_h = radv_device_to_handle(device);
129
130	struct radv_shader_module fs_module = {
131		.nir = build_nir_fs(),
132	};
133
134	if (!fs_module.nir) {
135		/* XXX: Need more accurate error */
136		result = VK_ERROR_OUT_OF_HOST_MEMORY;
137		goto cleanup;
138	}
139
140	const VkPipelineShaderStageCreateInfo stages[2] = {
141		{
142			.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
143			.stage = VK_SHADER_STAGE_VERTEX_BIT,
144			.module = vs_module_h,
145			.pName = "main",
146		},
147		{
148			.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
149			.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
150			.module = radv_shader_module_to_handle(&fs_module),
151			.pName = "main",
152		},
153	};
154
155	const VkPipelineVertexInputStateCreateInfo vi_state = {
156		.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
157		.vertexBindingDescriptionCount = 1,
158		.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
159			{
160				.binding = 0,
161				.stride = sizeof(struct vertex_attrs),
162				.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
163			},
164		},
165		.vertexAttributeDescriptionCount = 1,
166		.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
167			{
168				/* Position */
169				.location = 0,
170				.binding = 0,
171				.format = VK_FORMAT_R32G32_SFLOAT,
172				.offset = offsetof(struct vertex_attrs, position),
173			},
174		}
175	};
176
177	const VkPipelineInputAssemblyStateCreateInfo ia_state = {
178		.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
179		.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
180		.primitiveRestartEnable = false,
181	};
182
183	const VkPipelineColorBlendStateCreateInfo blend_state = {
184		.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
185		.logicOpEnable = false,
186		.attachmentCount = 1,
187		.pAttachments = (VkPipelineColorBlendAttachmentState []) {
188			{
189				.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
190				VK_COLOR_COMPONENT_G_BIT |
191				VK_COLOR_COMPONENT_B_BIT |
192				VK_COLOR_COMPONENT_A_BIT,
193			},
194		}
195	};
196	const VkPipelineRasterizationStateCreateInfo rs_state = {
197		.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
198		.depthClampEnable = false,
199		.rasterizerDiscardEnable = false,
200		.polygonMode = VK_POLYGON_MODE_FILL,
201		.cullMode = VK_CULL_MODE_NONE,
202		.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
203	};
204
205	result = radv_graphics_pipeline_create(device_h,
206					       radv_pipeline_cache_to_handle(&device->meta_state.cache),
207					       &(VkGraphicsPipelineCreateInfo) {
208						       .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
209						       .stageCount = 2,
210						       .pStages = stages,
211
212						       .pVertexInputState = &vi_state,
213						       .pInputAssemblyState = &ia_state,
214
215					       .pViewportState = &(VkPipelineViewportStateCreateInfo) {
216						       .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
217						       .viewportCount = 0,
218						       .scissorCount = 0,
219					       },
220						       .pRasterizationState = &rs_state,
221					       .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
222						       .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
223						       .rasterizationSamples = 1,
224						       .sampleShadingEnable = false,
225						       .pSampleMask = NULL,
226						       .alphaToCoverageEnable = false,
227						       .alphaToOneEnable = false,
228					       },
229						.pColorBlendState = &blend_state,
230						.pDynamicState = NULL,
231						.renderPass = device->meta_state.fast_clear_flush.pass,
232						.subpass = 0,
233					       },
234					       &(struct radv_graphics_pipeline_create_info) {
235						       .use_rectlist = true,
236						       .custom_blend_mode = V_028808_CB_ELIMINATE_FAST_CLEAR,
237					       },
238					       &device->meta_state.alloc,
239					       &device->meta_state.fast_clear_flush.cmask_eliminate_pipeline);
240	if (result != VK_SUCCESS)
241		goto cleanup;
242
243	result = radv_graphics_pipeline_create(device_h,
244					       radv_pipeline_cache_to_handle(&device->meta_state.cache),
245					       &(VkGraphicsPipelineCreateInfo) {
246						       .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
247						       .stageCount = 2,
248						       .pStages = stages,
249
250						       .pVertexInputState = &vi_state,
251						       .pInputAssemblyState = &ia_state,
252
253					       .pViewportState = &(VkPipelineViewportStateCreateInfo) {
254						       .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
255						       .viewportCount = 0,
256						       .scissorCount = 0,
257					       },
258						       .pRasterizationState = &rs_state,
259					       .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
260						       .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
261						       .rasterizationSamples = 1,
262						       .sampleShadingEnable = false,
263						       .pSampleMask = NULL,
264						       .alphaToCoverageEnable = false,
265						       .alphaToOneEnable = false,
266					       },
267						.pColorBlendState = &blend_state,
268						.pDynamicState = NULL,
269						.renderPass = device->meta_state.fast_clear_flush.pass,
270						.subpass = 0,
271					       },
272					       &(struct radv_graphics_pipeline_create_info) {
273						       .use_rectlist = true,
274						       .custom_blend_mode = V_028808_CB_FMASK_DECOMPRESS,
275					       },
276					       &device->meta_state.alloc,
277					       &device->meta_state.fast_clear_flush.fmask_decompress_pipeline);
278	if (result != VK_SUCCESS)
279		goto cleanup_cmask;
280
281	goto cleanup;
282cleanup_cmask:
283	radv_DestroyPipeline(device_h, device->meta_state.fast_clear_flush.cmask_eliminate_pipeline, &device->meta_state.alloc);
284cleanup:
285	ralloc_free(fs_module.nir);
286	return result;
287}
288
289void
290radv_device_finish_meta_fast_clear_flush_state(struct radv_device *device)
291{
292	struct radv_meta_state *state = &device->meta_state;
293	VkDevice device_h = radv_device_to_handle(device);
294	VkRenderPass pass_h = device->meta_state.fast_clear_flush.pass;
295	const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
296
297	if (pass_h)
298		radv_DestroyRenderPass(device_h, pass_h,
299					     &device->meta_state.alloc);
300
301	VkPipeline pipeline_h = state->fast_clear_flush.cmask_eliminate_pipeline;
302	if (pipeline_h) {
303		radv_DestroyPipeline(device_h, pipeline_h, alloc);
304	}
305
306	pipeline_h = state->fast_clear_flush.fmask_decompress_pipeline;
307	if (pipeline_h) {
308		radv_DestroyPipeline(device_h, pipeline_h, alloc);
309	}
310}
311
312VkResult
313radv_device_init_meta_fast_clear_flush_state(struct radv_device *device)
314{
315	VkResult res = VK_SUCCESS;
316
317	zero(device->meta_state.fast_clear_flush);
318
319	struct radv_shader_module vs_module = { .nir = build_nir_vs() };
320	if (!vs_module.nir) {
321		/* XXX: Need more accurate error */
322		res = VK_ERROR_OUT_OF_HOST_MEMORY;
323		goto fail;
324	}
325
326	res = create_pass(device);
327	if (res != VK_SUCCESS)
328		goto fail;
329
330	VkShaderModule vs_module_h = radv_shader_module_to_handle(&vs_module);
331	res = create_pipeline(device, vs_module_h);
332	if (res != VK_SUCCESS)
333		goto fail;
334
335	goto cleanup;
336
337fail:
338	radv_device_finish_meta_fast_clear_flush_state(device);
339
340cleanup:
341	ralloc_free(vs_module.nir);
342
343	return res;
344}
345
346static void
347emit_fast_clear_flush(struct radv_cmd_buffer *cmd_buffer,
348		      const VkExtent2D *resolve_extent,
349		      bool fmask_decompress)
350{
351	struct radv_device *device = cmd_buffer->device;
352	VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
353	uint32_t offset;
354	const struct vertex_attrs vertex_data[3] = {
355		{
356			.position = {
357				0,
358				0,
359			},
360		},
361		{
362			.position = {
363				0,
364				resolve_extent->height,
365			},
366		},
367		{
368			.position = {
369				resolve_extent->width,
370				0,
371			},
372		},
373	};
374
375	cmd_buffer->state.flush_bits |= (RADV_CMD_FLAG_FLUSH_AND_INV_CB |
376					 RADV_CMD_FLAG_FLUSH_AND_INV_CB_META);
377	radv_cmd_buffer_upload_data(cmd_buffer, sizeof(vertex_data), 16, vertex_data, &offset);
378	struct radv_buffer vertex_buffer = {
379		.device = device,
380		.size = sizeof(vertex_data),
381		.bo = cmd_buffer->upload.upload_bo,
382		.offset = offset,
383	};
384
385	VkBuffer vertex_buffer_h = radv_buffer_to_handle(&vertex_buffer);
386
387	radv_CmdBindVertexBuffers(cmd_buffer_h,
388				  /*firstBinding*/ 0,
389				  /*bindingCount*/ 1,
390				  (VkBuffer[]) { vertex_buffer_h },
391				  (VkDeviceSize[]) { 0 });
392
393	VkPipeline pipeline_h;
394	if (fmask_decompress)
395		pipeline_h = device->meta_state.fast_clear_flush.fmask_decompress_pipeline;
396	else
397		pipeline_h = device->meta_state.fast_clear_flush.cmask_eliminate_pipeline;
398	RADV_FROM_HANDLE(radv_pipeline, pipeline, pipeline_h);
399
400	if (cmd_buffer->state.pipeline != pipeline) {
401		radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
402				     pipeline_h);
403	}
404
405	radv_CmdDraw(cmd_buffer_h, 3, 1, 0, 0);
406	cmd_buffer->state.flush_bits |= (RADV_CMD_FLAG_FLUSH_AND_INV_CB |
407					 RADV_CMD_FLAG_FLUSH_AND_INV_CB_META);
408	si_emit_cache_flush(cmd_buffer);
409}
410
411/**
412 */
413void
414radv_fast_clear_flush_image_inplace(struct radv_cmd_buffer *cmd_buffer,
415				    struct radv_image *image)
416{
417	struct radv_meta_saved_state saved_state;
418	struct radv_meta_saved_pass_state saved_pass_state;
419	VkDevice device_h = radv_device_to_handle(cmd_buffer->device);
420	VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
421
422	assert(cmd_buffer->queue_family_index == RADV_QUEUE_GENERAL);
423	radv_meta_save_pass(&saved_pass_state, cmd_buffer);
424	radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer);
425
426	struct radv_image_view iview;
427	radv_image_view_init(&iview, cmd_buffer->device,
428			     &(VkImageViewCreateInfo) {
429				     .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
430					     .image = radv_image_to_handle(image),
431					     .format = image->vk_format,
432					     .subresourceRange = {
433						     .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
434						     .baseMipLevel = 0,
435						     .levelCount = 1,
436						     .baseArrayLayer = 0,
437						     .layerCount = 1,
438					     },
439				     },
440				     cmd_buffer, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
441
442	VkFramebuffer fb_h;
443	radv_CreateFramebuffer(device_h,
444			       &(VkFramebufferCreateInfo) {
445				       .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
446				       .attachmentCount = 1,
447				       .pAttachments = (VkImageView[]) {
448					       radv_image_view_to_handle(&iview)
449				       },
450				       .width = image->extent.width,
451				       .height = image->extent.height,
452				       .layers = 1
453			      },
454			      &cmd_buffer->pool->alloc,
455			      &fb_h);
456
457	radv_CmdBeginRenderPass(cmd_buffer_h,
458				      &(VkRenderPassBeginInfo) {
459					      .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
460						      .renderPass = cmd_buffer->device->meta_state.fast_clear_flush.pass,
461						      .framebuffer = fb_h,
462						      .renderArea = {
463						      .offset = {
464							      0,
465							      0,
466						      },
467						      .extent = {
468							      image->extent.width,
469							      image->extent.height,
470						      }
471					      },
472					      .clearValueCount = 0,
473					      .pClearValues = NULL,
474				     },
475				     VK_SUBPASS_CONTENTS_INLINE);
476
477	emit_fast_clear_flush(cmd_buffer,
478			      &(VkExtent2D) { image->extent.width, image->extent.height },
479			      image->fmask.size > 0);
480	radv_CmdEndRenderPass(cmd_buffer_h);
481
482	radv_DestroyFramebuffer(device_h, fb_h,
483				&cmd_buffer->pool->alloc);
484
485	radv_meta_restore(&saved_state, cmd_buffer);
486	radv_meta_restore_pass(&saved_pass_state, cmd_buffer);
487}
488