1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 //============================================================
4 //
5 //  chainentry.cpp - BGFX shader post-processing node
6 //
7 //  Represents a single entry in a list of post-processing
8 //  passes to be applied to a screen quad or buffer.
9 //
10 //============================================================
11 
12 #include "emu.h"
13 
14 #include <bgfx/bgfx.h>
15 #include <bx/math.h>
16 #include <cmath>
17 
18 #include "chainmanager.h"
19 #include "chainentry.h"
20 
21 #include "effect.h"
22 #include "clear.h"
23 #include "texture.h"
24 #include "target.h"
25 #include "entryuniform.h"
26 #include "texturemanager.h"
27 #include "vertex.h"
28 #include "suppressor.h"
29 
30 #include "render.h"
31 
32 
bgfx_chain_entry(std::string name,bgfx_effect * effect,clear_state * clear,std::vector<bgfx_suppressor * > suppressors,std::vector<bgfx_input_pair * > inputs,std::vector<bgfx_entry_uniform * > uniforms,target_manager & targets,std::string output,bool apply_tint)33 bgfx_chain_entry::bgfx_chain_entry(std::string name, bgfx_effect* effect, clear_state* clear, std::vector<bgfx_suppressor*> suppressors, std::vector<bgfx_input_pair*> inputs, std::vector<bgfx_entry_uniform*> uniforms, target_manager& targets, std::string output, bool apply_tint)
34 	: m_name(name)
35 	, m_effect(effect)
36 	, m_clear(clear)
37 	, m_suppressors(suppressors)
38 	, m_inputs(inputs)
39 	, m_uniforms(uniforms)
40 	, m_targets(targets)
41 	, m_output(output)
42 	, m_apply_tint(apply_tint)
43 {
44 }
45 
~bgfx_chain_entry()46 bgfx_chain_entry::~bgfx_chain_entry()
47 {
48 	for (bgfx_input_pair* input : m_inputs)
49 	{
50 		delete input;
51 	}
52 	m_inputs.clear();
53 	for (bgfx_entry_uniform* uniform : m_uniforms)
54 	{
55 		delete uniform;
56 	}
57 	m_uniforms.clear();
58 	delete m_clear;
59 }
60 
submit(int view,chain_manager::screen_prim & prim,texture_manager & textures,uint16_t screen_count,uint16_t screen_width,uint16_t screen_height,float screen_scale_x,float screen_scale_y,float screen_offset_x,float screen_offset_y,uint32_t rotation_type,bool swap_xy,uint64_t blend,int32_t screen)61 void bgfx_chain_entry::submit(int view, chain_manager::screen_prim &prim, texture_manager& textures, uint16_t screen_count, uint16_t screen_width, uint16_t screen_height, float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y, uint32_t rotation_type, bool swap_xy, uint64_t blend, int32_t screen)
62 {
63 	if (!setup_view(textures, view, screen_width, screen_height, screen))
64 	{
65 		return;
66 	}
67 
68 	for (bgfx_input_pair* input : m_inputs)
69 	{
70 		input->bind(m_effect, screen);
71 	}
72 
73 	uint32_t tint = 0xffffffff;
74 	if (m_apply_tint)
75 	{
76 		const auto a = (uint8_t)std::round(prim.m_prim->color.a * 255);
77 		const auto r = (uint8_t)std::round(prim.m_prim->color.r * 255);
78 		const auto g = (uint8_t)std::round(prim.m_prim->color.g * 255);
79 		const auto b = (uint8_t)std::round(prim.m_prim->color.b * 255);
80 		tint = (a << 24) | (b << 16) | (g << 8) | r;
81 	}
82 
83 	bgfx::TransientVertexBuffer buffer;
84 	put_screen_buffer(prim.m_screen_width, prim.m_screen_height, tint, &buffer);
85 	bgfx::setVertexBuffer(0, &buffer);
86 
87 	setup_auto_uniforms(prim, textures, screen_count, screen_width, screen_height, screen_scale_x, screen_scale_y, screen_offset_x, screen_offset_y, rotation_type, swap_xy, screen);
88 
89 	for (bgfx_entry_uniform* uniform : m_uniforms)
90 	{
91 		if (uniform->name() != "s_tex")
92 		{
93 			uniform->bind();
94 		}
95 	}
96 
97 	m_effect->submit(view, blend);
98 
99 	if (m_targets.target(screen, m_output) != nullptr)
100 	{
101 		m_targets.target(screen, m_output)->page_flip();
102 	}
103 }
104 
setup_screensize_uniforms(texture_manager & textures,uint16_t screen_width,uint16_t screen_height,int32_t screen)105 void bgfx_chain_entry::setup_screensize_uniforms(texture_manager& textures, uint16_t screen_width, uint16_t screen_height, int32_t screen)
106 {
107 	float width = screen_width;
108 	float height = screen_height;
109 	if (m_inputs.size() > 0)
110 	{
111 		std::string name = m_inputs[0]->texture() + std::to_string(screen);
112 		width = float(textures.provider(name)->width());
113 		height = float(textures.provider(name)->height());
114 	}
115 
116 	bgfx_uniform* screen_dims = m_effect->uniform("u_screen_dims");
117 	if (screen_dims != nullptr)
118 	{
119 		float values[2] = { width, height };
120 		screen_dims->set(values, sizeof(float) * 2);
121 	}
122 
123 	bgfx_uniform* inv_screen_dims = m_effect->uniform("u_inv_screen_dims");
124 	if (inv_screen_dims != nullptr)
125 	{
126 		float values[2] = { 1.0f / width, 1.0f / height };
127 		inv_screen_dims->set(values, sizeof(float) * 2);
128 	}
129 }
130 
setup_screenscale_uniforms(float screen_scale_x,float screen_scale_y)131 void bgfx_chain_entry::setup_screenscale_uniforms(float screen_scale_x, float screen_scale_y)
132 {
133 	bgfx_uniform* screen_scale = m_effect->uniform("u_screen_scale");
134 	if (screen_scale != nullptr)
135 	{
136 		float values[2] = { screen_scale_x, screen_scale_y };
137 		screen_scale->set(values, sizeof(float) * 2);
138 	}
139 }
140 
setup_screenoffset_uniforms(float screen_offset_x,float screen_offset_y)141 void bgfx_chain_entry::setup_screenoffset_uniforms(float screen_offset_x, float screen_offset_y)
142 {
143 	bgfx_uniform* screen_offset = m_effect->uniform("u_screen_offset");
144 	if (screen_offset != nullptr)
145 	{
146 		float values[2] = { screen_offset_x, screen_offset_y };
147 		screen_offset->set(values, sizeof(float) * 2);
148 	}
149 }
150 
setup_screencount_uniforms(uint16_t screen_count)151 void bgfx_chain_entry::setup_screencount_uniforms(uint16_t screen_count)
152 {
153 	bgfx_uniform* u_screen_count = m_effect->uniform("u_screen_count");
154 	if (u_screen_count != nullptr)
155 	{
156 		float values[1] = { float(screen_count) };
157 		u_screen_count->set(values, sizeof(float));
158 	}
159 }
160 
setup_sourcesize_uniform(chain_manager::screen_prim & prim) const161 void bgfx_chain_entry::setup_sourcesize_uniform(chain_manager::screen_prim &prim) const
162 {
163 	bgfx_uniform* source_dims = m_effect->uniform("u_source_dims");
164 	if (source_dims != nullptr)
165 	{
166 		source_dims->set(&prim.m_tex_width, sizeof(float) * 2);
167 	}
168 }
169 
setup_targetsize_uniform(int32_t screen) const170 void bgfx_chain_entry::setup_targetsize_uniform(int32_t screen) const
171 {
172 	bgfx_uniform* target_dims = m_effect->uniform("u_target_dims");
173 	if (target_dims != nullptr)
174 	{
175 		bgfx_target* output = m_targets.target(screen, m_output);
176 		if (output != nullptr)
177 		{
178 			float values[2] = { float(output->width()), float(output->height()) };
179 			target_dims->set(values, sizeof(float) * 2);
180 		}
181 	}
182 }
183 
setup_targetscale_uniform(int32_t screen) const184 void bgfx_chain_entry::setup_targetscale_uniform(int32_t screen) const
185 {
186 	bgfx_uniform* target_scale = m_effect->uniform("u_target_scale");
187 	if (target_scale != nullptr)
188 	{
189 		bgfx_target* output = m_targets.target(screen, m_output);
190 		if (output != nullptr)
191 		{
192 			float values[2] = { float(output->scale()), float(output->scale()) };
193 			target_scale->set(values, sizeof(float) * 2);
194 		}
195 	}
196 }
197 
setup_rotationtype_uniform(uint32_t rotation_type) const198 void bgfx_chain_entry::setup_rotationtype_uniform(uint32_t rotation_type) const
199 {
200 	bgfx_uniform* rotation_type_uniform = m_effect->uniform("u_rotation_type");
201 	if (rotation_type_uniform != nullptr)
202 	{
203 		float values[1] = { float(rotation_type) };
204 		rotation_type_uniform->set(values, sizeof(float));
205 	}
206 }
207 
setup_swapxy_uniform(bool swap_xy) const208 void bgfx_chain_entry::setup_swapxy_uniform(bool swap_xy) const
209 {
210 	bgfx_uniform* swap_xy_uniform = m_effect->uniform("u_swap_xy");
211 	if (swap_xy_uniform != nullptr)
212 	{
213 		float values[1] = { swap_xy ? 1.0f : 0.0f };
214 		swap_xy_uniform->set(values, sizeof(float));
215 	}
216 }
217 
setup_quaddims_uniform(chain_manager::screen_prim & prim) const218 void bgfx_chain_entry::setup_quaddims_uniform(chain_manager::screen_prim &prim) const
219 {
220 	bgfx_uniform* quad_dims_uniform = m_effect->uniform("u_quad_dims");
221 	if (quad_dims_uniform != nullptr)
222 	{
223 		float values[2] = { float(prim.m_quad_width), float(prim.m_quad_height) };
224 		quad_dims_uniform->set(values, sizeof(float) * 2);
225 	}
226 }
227 
setup_screenindex_uniform(int32_t screen) const228 void bgfx_chain_entry::setup_screenindex_uniform(int32_t screen) const
229 {
230 	bgfx_uniform* screen_index = m_effect->uniform("u_screen_index");
231 	if (screen_index != nullptr)
232 	{
233 		float values[1] = { float(screen) };
234 		screen_index->set(values, sizeof(float));
235 	}
236 }
237 
setup_auto_uniforms(chain_manager::screen_prim & prim,texture_manager & textures,uint16_t screen_count,uint16_t screen_width,uint16_t screen_height,float screen_scale_x,float screen_scale_y,float screen_offset_x,float screen_offset_y,uint32_t rotation_type,bool swap_xy,int32_t screen)238 void bgfx_chain_entry::setup_auto_uniforms(chain_manager::screen_prim &prim, texture_manager& textures, uint16_t screen_count, uint16_t screen_width, uint16_t screen_height, float screen_scale_x, float screen_scale_y, float screen_offset_x, float screen_offset_y, uint32_t rotation_type, bool swap_xy, int32_t screen)
239 {
240 	setup_screensize_uniforms(textures, screen_width, screen_height, screen);
241 	setup_screenscale_uniforms(screen_scale_x, screen_scale_y);
242 	setup_screenoffset_uniforms(screen_offset_x, screen_offset_y);
243 	setup_screencount_uniforms(screen_count);
244 	setup_sourcesize_uniform(prim);
245 	setup_targetsize_uniform(screen);
246 	setup_targetscale_uniform(screen);
247 	setup_rotationtype_uniform(rotation_type);
248 	setup_swapxy_uniform(swap_xy);
249 	setup_quaddims_uniform(prim);
250 	setup_screenindex_uniform(screen);
251 }
252 
setup_view(texture_manager & textures,int view,uint16_t screen_width,uint16_t screen_height,int32_t screen) const253 bool bgfx_chain_entry::setup_view(texture_manager &textures, int view, uint16_t screen_width, uint16_t screen_height, int32_t screen) const
254 {
255 	bgfx::FrameBufferHandle handle = BGFX_INVALID_HANDLE;
256 	uint16_t width = screen_width;
257 	uint16_t height = screen_height;
258 	if (m_targets.target(screen, m_output) != nullptr)
259 	{
260 		bgfx_target* output = m_targets.target(screen, m_output);
261 		if (output->width() == 0)
262 		{
263 			return false;
264 		}
265 		handle = output->target();
266 		width = output->width();
267 		height = output->height();
268 	}
269 
270 	bgfx::setViewFrameBuffer(view, handle);
271 	bgfx::setViewRect(view, 0, 0, width, height);
272 
273 	const bgfx::Caps* caps = bgfx::getCaps();
274 
275 	std::string name = m_inputs[0]->texture() + std::to_string(screen);
276 	const float right_ratio = (float)textures.provider(name)->width() / textures.provider(name)->rowpixels();
277 
278 	float projMat[16];
279 	bx::mtxOrtho(projMat, 0.0f, right_ratio, 1.0f, 0.0f, 0.0f, 100.0f, 0.0f, caps->homogeneousDepth);
280 	bgfx::setViewTransform(view, nullptr, projMat);
281 
282 	m_clear->bind(view);
283 	return true;
284 }
285 
put_screen_buffer(uint16_t screen_width,uint16_t screen_height,uint32_t screen_tint,bgfx::TransientVertexBuffer * buffer) const286 void bgfx_chain_entry::put_screen_buffer(uint16_t screen_width, uint16_t screen_height, uint32_t screen_tint, bgfx::TransientVertexBuffer* buffer) const
287 {
288 	if (6 == bgfx::getAvailTransientVertexBuffer(6, ScreenVertex::ms_decl))
289 	{
290 		bgfx::allocTransientVertexBuffer(buffer, 6, ScreenVertex::ms_decl);
291 	}
292 	else
293 	{
294 		return;
295 	}
296 
297 	auto* vertex = reinterpret_cast<ScreenVertex*>(buffer->data);
298 
299 	float x[4] = { 0, 1, 0, 1 };
300 	float y[4] = { 0, 0, 1, 1 };
301 	float u[4] = { 0, 1, 0, 1 };
302 	float v[4] = { 0, 0, 1, 1 };
303 
304 	bgfx::RendererType::Enum renderer_type = bgfx::getRendererType();
305 	if (renderer_type == bgfx::RendererType::OpenGL || renderer_type == bgfx::RendererType::OpenGLES)
306 	{
307 		v[0] = v[1] = 1;
308 		v[2] = v[3] = 0;
309 	}
310 	else if (renderer_type == bgfx::RendererType::Direct3D9)
311 	{
312 		for (int i = 0; i < 4; i++)
313 		{
314 			u[i] += 0.5f / screen_width;
315 			v[i] += 0.5f / screen_height;
316 		}
317 	}
318 
319 	vertex[0].m_x = x[0];
320 	vertex[0].m_y = y[0];
321 	vertex[0].m_z = 0;
322 	vertex[0].m_rgba = screen_tint;
323 	vertex[0].m_u = u[0];
324 	vertex[0].m_v = v[0];
325 
326 	vertex[1].m_x = x[1];
327 	vertex[1].m_y = y[1];
328 	vertex[1].m_z = 0;
329 	vertex[1].m_rgba = screen_tint;
330 	vertex[1].m_u = u[1];
331 	vertex[1].m_v = v[1];
332 
333 	vertex[2].m_x = x[3];
334 	vertex[2].m_y = y[3];
335 	vertex[2].m_z = 0;
336 	vertex[2].m_rgba = screen_tint;
337 	vertex[2].m_u = u[3];
338 	vertex[2].m_v = v[3];
339 
340 	vertex[3].m_x = x[3];
341 	vertex[3].m_y = y[3];
342 	vertex[3].m_z = 0;
343 	vertex[3].m_rgba = screen_tint;
344 	vertex[3].m_u = u[3];
345 	vertex[3].m_v = v[3];
346 
347 	vertex[4].m_x = x[2];
348 	vertex[4].m_y = y[2];
349 	vertex[4].m_z = 0;
350 	vertex[4].m_rgba = screen_tint;
351 	vertex[4].m_u = u[2];
352 	vertex[4].m_v = v[2];
353 
354 	vertex[5].m_x = x[0];
355 	vertex[5].m_y = y[0];
356 	vertex[5].m_z = 0;
357 	vertex[5].m_rgba = screen_tint;
358 	vertex[5].m_u = u[0];
359 	vertex[5].m_v = v[0];
360 }
361 
skip()362 bool bgfx_chain_entry::skip()
363 {
364 	if (m_suppressors.size() == 0)
365 	{
366 		return false;
367 	}
368 
369 	// Group all AND/OR'd results together and OR them together (hack for now)
370 	// TODO: Make this a bit more logical
371 
372 	bool or_suppress = false;
373 	int and_count = 0;
374 	int and_suppressed = 0;
375 	for (bgfx_suppressor* suppressor : m_suppressors)
376 	{
377 		if (suppressor->combine() == bgfx_suppressor::combine_mode::COMBINE_AND)
378 		{
379 			and_count++;
380 			if (suppressor->suppress())
381 			{
382 				and_suppressed++;
383 			}
384 		}
385 		else if (suppressor->combine() == bgfx_suppressor::combine_mode::COMBINE_OR)
386 		{
387 			or_suppress |= suppressor->suppress();
388 		}
389 	}
390 
391 	return (and_count != 0 && and_suppressed == and_count) || or_suppress;
392 }
393