1 #include "GPUDriverTestScreen.h"
2 #include "Common/Data/Text/I18n.h"
3 #include "Common/UI/View.h"
4 #include "Common/GPU/Shader.h"
5 #include "Common/GPU/ShaderWriter.h"
6 
7 const uint32_t textColorOK = 0xFF30FF30;
8 const uint32_t textColorBAD = 0xFF3030FF;
9 const uint32_t bgColorOK = 0xFF106010;
10 const uint32_t bgColorBAD = 0xFF101060;
11 
12 // TODO: One day, port these to use ShaderWriter.
13 
14 static const std::vector<Draw::ShaderSource> fsDiscard = {
15 	{ShaderLanguage::GLSL_1xx,
16 	R"(
17 	#ifdef GL_ES
18 	precision lowp float;
19 	#endif
20 	#if __VERSION__ >= 130
21 	#define varying in
22 	#define gl_FragColor fragColor0
23 	out vec4 fragColor0;
24 	#endif
25 	varying vec4 oColor0;
26 	varying vec2 oTexCoord0;
27 	uniform sampler2D Sampler0;
28 	void main() {
29 	#if __VERSION__ >= 130
30 		vec4 color = texture(Sampler0, oTexCoord0) * oColor0;
31 	#else
32 		vec4 color = texture2D(Sampler0, oTexCoord0) * oColor0;
33 	#endif
34 		if (color.a <= 0.0)
35 			discard;
36 		gl_FragColor = color;
37 	})"
38 	},
39 	{ShaderLanguage::GLSL_VULKAN,
40 	R"(#version 450
41 	#extension GL_ARB_separate_shader_objects : enable
42 	#extension GL_ARB_shading_language_420pack : enable
43 	layout(location = 0) in vec4 oColor0;
44 	layout(location = 1) in vec2 oTexCoord0;
45 	layout(location = 0) out vec4 fragColor0;
46 	layout(set = 0, binding = 1) uniform sampler2D Sampler0;
47 	void main() {
48 		vec4 color = texture(Sampler0, oTexCoord0) * oColor0;
49 		if (color.a <= 0.0)
50 			discard;
51 		fragColor0 = color;
52 	})"
53 	},
54 };
55 
56 static const std::vector<Draw::ShaderSource> fsAdrenoLogicTest = {
57 	{ShaderLanguage::GLSL_1xx,
58 	R"(
59 	#ifdef GL_ES
60 	precision lowp float;
61 	#endif
62 	#if __VERSION__ >= 130
63 	#define varying in
64 	#define gl_FragColor fragColor0
65 	out vec4 fragColor0;
66 	#endif
67 	varying vec4 oColor0;
68 	varying vec2 oTexCoord0;
69 	uniform sampler2D Sampler0;
70 	void main() {
71 	#if __VERSION__ >= 130
72 		vec4 color = (texture(Sampler0, oTexCoord0) * oColor0).aaaa;
73 	#else
74 		vec4 color = (texture2D(Sampler0, oTexCoord0) * oColor0).aaaa;
75 	#endif
76 		color *= 2.0;
77 		if (color.r < 0.002 && color.g < 0.002 && color.b < 0.002) discard;
78 		gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
79 	})"
80 	},
81 	{ShaderLanguage::GLSL_VULKAN,
82 	R"(#version 450
83 	#extension GL_ARB_separate_shader_objects : enable
84 	#extension GL_ARB_shading_language_420pack : enable
85 	layout(location = 0) in vec4 oColor0;
86 	layout(location = 1) in highp vec2 oTexCoord0;
87 	layout(location = 0) out vec4 fragColor0;
88 	layout(set = 0, binding = 1) uniform sampler2D Sampler0;
89 	void main() {
90 		vec4 v = texture(Sampler0, oTexCoord0).aaaa * oColor0;
91 		if (v.r < 0.2 && v.g < 0.2 && v.b < 0.2) discard;
92 		fragColor0 = vec4(0.0, 1.0, 0.0, 1.0);
93 	})"
94 	},
95 };
96 
97 static const std::vector<Draw::ShaderSource> vsAdrenoLogicTest = {
98 	{ GLSL_1xx,
99 	"#if __VERSION__ >= 130\n"
100 	"#define attribute in\n"
101 	"#define varying out\n"
102 	"#endif\n"
103 	"attribute vec3 Position;\n"
104 	"attribute vec4 Color0;\n"
105 	"attribute vec2 TexCoord0;\n"
106 	"varying vec4 oColor0;\n"
107 	"varying vec2 oTexCoord0;\n"
108 	"uniform mat4 WorldViewProj;\n"
109 	"void main() {\n"
110 	"  gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
111 	"  oColor0 = Color0;\n"
112 	"  oTexCoord0 = TexCoord0;\n"
113 	"}\n"
114 	},
115 	{ ShaderLanguage::GLSL_VULKAN,
116 	"#version 450\n"
117 	"#extension GL_ARB_separate_shader_objects : enable\n"
118 	"#extension GL_ARB_shading_language_420pack : enable\n"
119 	"layout (std140, set = 0, binding = 0) uniform bufferVals {\n"
120 	"    mat4 WorldViewProj;\n"
121 	"} myBufferVals;\n"
122 	"layout (location = 0) in vec4 pos;\n"
123 	"layout (location = 1) in vec4 inColor;\n"
124 	"layout (location = 2) in vec2 inTexCoord;\n"
125 	"layout (location = 0) out vec4 outColor;\n"
126 	"layout (location = 1) out highp vec2 outTexCoord;\n"
127 	"out gl_PerVertex { vec4 gl_Position; };\n"
128 	"void main() {\n"
129 	"   outColor = inColor;\n"
130 	"   outTexCoord = inTexCoord;\n"
131 	"   gl_Position = myBufferVals.WorldViewProj * pos;\n"
132 	"}\n"
133 	}
134 };
135 
136 static const std::vector<Draw::ShaderSource> fsFlat = {
137 	{ShaderLanguage::GLSL_3xx,
138 	"#ifdef GL_ES\n"
139 	"precision lowp float;\n"
140 	"precision highp int;\n"
141 	"#endif\n"
142 	"uniform sampler2D Sampler0;\n"
143 	"flat in lowp vec4 oColor0;\n"
144 	"in mediump vec3 oTexCoord0;\n"
145 	"out vec4 fragColor0;\n"
146 	"void main() {\n"
147 	"  vec4 t = texture(Sampler0, oTexCoord0.xy);\n"
148 	"  vec4 p = oColor0;\n"
149 	"  vec4 v = p * t;\n"
150 	"  fragColor0 = v;\n"
151 	"}\n"
152 	},
153 	{ShaderLanguage::GLSL_1xx,
154 	"#ifdef GL_ES\n"
155 	"precision lowp float;\n"
156 	"#endif\n"
157 	"#if __VERSION__ >= 130\n"
158 	"#define varying in\n"
159 	"#define texture2D texture\n"
160 	"#define gl_FragColor fragColor0\n"
161 	"out vec4 fragColor0;\n"
162 	"#endif\n"
163 	"varying vec4 oColor0;\n"
164 	"varying vec2 oTexCoord0;\n"
165 	"uniform sampler2D Sampler0;\n"
166 	"void main() { gl_FragColor = texture2D(Sampler0, oTexCoord0) * oColor0; }\n"
167 	},
168 	{ShaderLanguage::GLSL_VULKAN,
169 	"#version 450\n"
170 	"#extension GL_ARB_separate_shader_objects : enable\n"
171 	"#extension GL_ARB_shading_language_420pack : enable\n"
172 	"layout(location = 0) flat in lowp vec4 oColor0;\n"
173 	"layout(location = 1) in highp vec2 oTexCoord0;\n"
174 	"layout(location = 0) out vec4 fragColor0;\n"
175 	"layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n"
176 	"void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n"
177 	}
178 };
179 
180 static const std::vector<Draw::ShaderSource> vsFlat = {
181 	{ GLSL_3xx,
182 	"in vec3 Position;\n"
183 	"in vec2 TexCoord0;\n"
184 	"in lowp vec4 Color0;\n"
185 	"uniform mat4 WorldViewProj;\n"
186 	"flat out lowp vec4 oColor0;\n"
187 	"out mediump vec3 oTexCoord0;\n"
188 	"void main() {\n"
189 	"  oTexCoord0 = vec3(TexCoord0, 1.0);\n"
190 	"  oColor0 = Color0;\n"
191 	"  vec4 outPos = WorldViewProj * vec4(Position, 1.0);\n"
192 	"  gl_Position = outPos;\n"
193 	"}\n"
194 	},
195 	{ GLSL_1xx,  // Doesn't actually repro the problem since flat support isn't guaranteed
196 	"#if __VERSION__ >= 130\n"
197 	"#define attribute in\n"
198 	"#define varying out\n"
199 	"#endif\n"
200 	"attribute vec3 Position;\n"
201 	"attribute vec4 Color0;\n"
202 	"attribute vec2 TexCoord0;\n"
203 	"varying vec4 oColor0;\n"
204 	"varying vec2 oTexCoord0;\n"
205 	"uniform mat4 WorldViewProj;\n"
206 	"void main() {\n"
207 	"  gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
208 	"  oColor0 = Color0;\n"
209 	"  oTexCoord0 = TexCoord0;\n"
210 	"}\n"
211 	},
212 	{ ShaderLanguage::GLSL_VULKAN,
213 	"#version 450\n"
214 	"#extension GL_ARB_separate_shader_objects : enable\n"
215 	"#extension GL_ARB_shading_language_420pack : enable\n"
216 	"layout (std140, set = 0, binding = 0) uniform bufferVals {\n"
217 	"    mat4 WorldViewProj;\n"
218 	"} myBufferVals;\n"
219 	"layout (location = 0) in vec4 pos;\n"
220 	"layout (location = 1) in vec4 inColor;\n"
221 	"layout (location = 2) in vec2 inTexCoord;\n"
222 	"layout (location = 0) flat out lowp vec4 outColor;\n"
223 	"layout (location = 1) out highp vec2 outTexCoord;\n"
224 	"out gl_PerVertex { vec4 gl_Position; };\n"
225 	"void main() {\n"
226 	"   outColor = inColor;\n"
227 	"   outTexCoord = inTexCoord;\n"
228 	"   gl_Position = myBufferVals.WorldViewProj * pos;\n"
229 	"}\n"
230 	}
231 };
232 
GPUDriverTestScreen()233 GPUDriverTestScreen::GPUDriverTestScreen() {
234 	using namespace Draw;
235 }
236 
~GPUDriverTestScreen()237 GPUDriverTestScreen::~GPUDriverTestScreen() {
238 	if (discardWriteDepthStencil_)
239 		discardWriteDepthStencil_->Release();
240 	if (discardWriteDepth_)
241 		discardWriteDepth_->Release();
242 	if (discardWriteStencil_)
243 		discardWriteStencil_->Release();
244 
245 	if (drawTestStencilEqualDepthAlways_)
246 		drawTestStencilEqualDepthAlways_->Release();
247 	if (drawTestStencilNotEqualDepthAlways_)
248 		drawTestStencilNotEqualDepthAlways_->Release();
249 	if (drawTestStencilEqual_)
250 		drawTestStencilEqual_->Release();
251 	if (drawTestStencilNotEqual_)
252 		drawTestStencilNotEqual_->Release();
253 	if (drawTestStencilAlwaysDepthLessEqual_)
254 		drawTestStencilAlwaysDepthLessEqual_->Release();
255 	if (drawTestStencilAlwaysDepthGreater_)
256 		drawTestStencilAlwaysDepthGreater_->Release();
257 	if (drawTestDepthLessEqual_)
258 		drawTestDepthLessEqual_->Release();
259 	if (drawTestDepthGreater_)
260 		drawTestDepthGreater_->Release();
261 
262 	if (discardFragShader_)
263 		discardFragShader_->Release();
264 
265 	// Shader test
266 	if (adrenoLogicDiscardPipeline_)
267 		adrenoLogicDiscardPipeline_->Release();
268 	if (flatShadingPipeline_)
269 		flatShadingPipeline_->Release();
270 
271 	if (adrenoLogicDiscardFragShader_)
272 		adrenoLogicDiscardFragShader_->Release();
273 	if (adrenoLogicDiscardVertShader_)
274 		adrenoLogicDiscardVertShader_->Release();
275 	if (flatFragShader_)
276 		flatFragShader_->Release();
277 	if (flatVertShader_)
278 		flatVertShader_->Release();
279 
280 	if (samplerNearest_)
281 		samplerNearest_->Release();
282 }
283 
CreateViews()284 void GPUDriverTestScreen::CreateViews() {
285 	using namespace Draw;
286 
287 	if (!samplerNearest_) {
288 		DrawContext *draw = screenManager()->getDrawContext();
289 		SamplerStateDesc nearestDesc{};
290 		samplerNearest_ = draw->CreateSamplerState(nearestDesc);
291 	}
292 
293 	// Don't bother with views for now.
294 	using namespace UI;
295 	auto di = GetI18NCategory("Dialog");
296 	auto cr = GetI18NCategory("PSPCredits");
297 
298 	AnchorLayout *anchor = new AnchorLayout();
299 	root_ = anchor;
300 
301 	tabHolder_ = new TabHolder(ORIENT_HORIZONTAL, 30.0f, new AnchorLayoutParams(FILL_PARENT, FILL_PARENT, false));
302 	anchor->Add(tabHolder_);
303 	tabHolder_->AddTab("Discard", new LinearLayout(ORIENT_VERTICAL));
304 	tabHolder_->AddTab("Shader", new LinearLayout(ORIENT_VERTICAL));
305 
306 	Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(100, WRAP_CONTENT, 10, NONE, NONE, 10));
307 	back->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
308 	anchor->Add(back);
309 }
310 
DiscardTest()311 void GPUDriverTestScreen::DiscardTest() {
312 	using namespace UI;
313 	using namespace Draw;
314 	if (!discardWriteDepthStencil_) {
315 		DrawContext *draw = screenManager()->getDrawContext();
316 
317 		// Create the special shader module.
318 
319 		discardFragShader_ = CreateShader(draw, ShaderStage::Fragment, fsDiscard);
320 
321 		InputLayout *inputLayout = ui_draw2d.CreateInputLayout(draw);
322 		BlendState *blendOff = draw->CreateBlendState({ false, 0xF });
323 
324 		// Write depth, write stencil.
325 		DepthStencilStateDesc dsDesc{};
326 		dsDesc.depthTestEnabled = true;
327 		dsDesc.depthWriteEnabled = true;
328 		dsDesc.depthCompare = Comparison::ALWAYS;
329 		dsDesc.stencilEnabled = true;
330 		dsDesc.front.compareMask = 0xFF;
331 		dsDesc.front.compareOp = Comparison::ALWAYS;
332 		dsDesc.front.passOp = StencilOp::REPLACE;
333 		dsDesc.front.failOp = StencilOp::ZERO;
334 		dsDesc.front.depthFailOp = StencilOp::ZERO;
335 		dsDesc.front.writeMask = 0xFF;
336 		dsDesc.back = dsDesc.front;
337 		DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc);
338 
339 		// Write only depth.
340 		dsDesc.stencilEnabled = false;
341 		DepthStencilState *depthWrite = draw->CreateDepthStencilState(dsDesc);
342 
343 		// Write only stencil.
344 		dsDesc.stencilEnabled = true;
345 		dsDesc.depthTestEnabled = false;
346 		dsDesc.depthWriteEnabled = false;  // Just in case the driver is crazy. when test is enabled, though, this should be ignored.
347 		DepthStencilState *stencilWrite = draw->CreateDepthStencilState(dsDesc);
348 
349 		// Now for the shaders that read depth and/or stencil.
350 
351 		dsDesc.depthTestEnabled = true;
352 		dsDesc.stencilEnabled = true;
353 		dsDesc.depthCompare = Comparison::ALWAYS;
354 		dsDesc.front.compareOp = Comparison::EQUAL;
355 		dsDesc.back = dsDesc.front;
356 		DepthStencilState *stencilEqualDepthAlways = draw->CreateDepthStencilState(dsDesc);
357 
358 		dsDesc.depthTestEnabled = false;
359 		dsDesc.front.compareOp = Comparison::EQUAL;
360 		dsDesc.back = dsDesc.front;
361 		DepthStencilState *stencilEqual = draw->CreateDepthStencilState(dsDesc);
362 
363 		dsDesc.depthTestEnabled = true;
364 		dsDesc.depthCompare = Comparison::ALWAYS;
365 		dsDesc.front.compareOp = Comparison::NOT_EQUAL;
366 		dsDesc.back = dsDesc.front;
367 		DepthStencilState *stenciNotEqualDepthAlways = draw->CreateDepthStencilState(dsDesc);
368 
369 		dsDesc.depthTestEnabled = false;
370 		dsDesc.front.compareOp = Comparison::NOT_EQUAL;
371 		dsDesc.back = dsDesc.front;
372 		DepthStencilState *stencilNotEqual = draw->CreateDepthStencilState(dsDesc);
373 
374 		dsDesc.stencilEnabled = true;
375 		dsDesc.depthTestEnabled = true;
376 		dsDesc.front.compareOp = Comparison::ALWAYS;
377 		dsDesc.back = dsDesc.front;
378 		dsDesc.depthCompare = Comparison::LESS_EQUAL;
379 		DepthStencilState *stencilAlwaysDepthTestLessEqual = draw->CreateDepthStencilState(dsDesc);
380 		dsDesc.depthCompare = Comparison::GREATER;
381 		DepthStencilState *stencilAlwaysDepthTestGreater = draw->CreateDepthStencilState(dsDesc);
382 
383 		dsDesc.stencilEnabled = false;
384 		dsDesc.depthTestEnabled = true;
385 		dsDesc.depthCompare = Comparison::LESS_EQUAL;
386 		DepthStencilState *depthTestLessEqual = draw->CreateDepthStencilState(dsDesc);
387 		dsDesc.depthCompare = Comparison::GREATER;
388 		DepthStencilState *depthTestGreater = draw->CreateDepthStencilState(dsDesc);
389 
390 		RasterState *rasterNoCull = draw->CreateRasterState({});
391 
392 		PipelineDesc discardDesc{
393 			Primitive::TRIANGLE_LIST,
394 			{ draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), discardFragShader_ },
395 			inputLayout, depthStencilWrite, blendOff, rasterNoCull, &vsColBufDesc,
396 		};
397 		discardWriteDepthStencil_ = draw->CreateGraphicsPipeline(discardDesc);
398 		discardDesc.depthStencil = depthWrite;
399 		discardWriteDepth_ = draw->CreateGraphicsPipeline(discardDesc);
400 		discardDesc.depthStencil = stencilWrite;
401 		discardWriteStencil_ = draw->CreateGraphicsPipeline(discardDesc);
402 
403 		PipelineDesc testDesc{
404 			Primitive::TRIANGLE_LIST,
405 			{ draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) },
406 			inputLayout, stencilEqual, blendOff, rasterNoCull, &vsColBufDesc,
407 		};
408 		drawTestStencilEqual_ = draw->CreateGraphicsPipeline(testDesc);
409 
410 		testDesc.depthStencil = stencilEqualDepthAlways;
411 		drawTestStencilEqualDepthAlways_ = draw->CreateGraphicsPipeline(testDesc);
412 
413 		testDesc.depthStencil = stencilNotEqual;
414 		drawTestStencilNotEqual_ = draw->CreateGraphicsPipeline(testDesc);
415 
416 		testDesc.depthStencil = stenciNotEqualDepthAlways;
417 		drawTestStencilNotEqualDepthAlways_ = draw->CreateGraphicsPipeline(testDesc);
418 
419 		testDesc.depthStencil = stencilAlwaysDepthTestGreater;
420 		drawTestStencilAlwaysDepthGreater_ = draw->CreateGraphicsPipeline(testDesc);
421 
422 		testDesc.depthStencil = stencilAlwaysDepthTestLessEqual;
423 		drawTestStencilAlwaysDepthLessEqual_ = draw->CreateGraphicsPipeline(testDesc);
424 
425 		testDesc.depthStencil = depthTestGreater;
426 		drawTestDepthGreater_ = draw->CreateGraphicsPipeline(testDesc);
427 
428 		testDesc.depthStencil = depthTestLessEqual;
429 		drawTestDepthLessEqual_ = draw->CreateGraphicsPipeline(testDesc);
430 
431 		inputLayout->Release();
432 		blendOff->Release();
433 		depthStencilWrite->Release();
434 		stencilEqual->Release();
435 		stencilNotEqual->Release();
436 		stencilEqualDepthAlways->Release();
437 		stenciNotEqualDepthAlways->Release();
438 		stencilAlwaysDepthTestLessEqual->Release();
439 		stencilAlwaysDepthTestGreater->Release();
440 		depthTestLessEqual->Release();
441 		depthTestGreater->Release();
442 		rasterNoCull->Release();
443 	}
444 
445 	UIContext &dc = *screenManager()->getUIContext();
446 	Draw::DrawContext *draw = dc.GetDrawContext();
447 
448 	static const char * const writeModeNames[] = { "Stencil+Depth", "Stencil", "Depth" };
449 	Pipeline *writePipelines[] = { discardWriteDepthStencil_, discardWriteStencil_, discardWriteDepth_ };
450 	const int numWriteModes = ARRAY_SIZE(writeModeNames);
451 
452 	static const char * const testNames[] = { "Stenc", "Stenc+DepthA", "Depth", "StencA+Depth" };
453 	Pipeline *testPipeline1[] = { drawTestStencilEqual_, drawTestStencilEqualDepthAlways_, drawTestDepthLessEqual_, drawTestStencilAlwaysDepthLessEqual_ };
454 	Pipeline *testPipeline2[] = { drawTestStencilNotEqual_, drawTestStencilNotEqualDepthAlways_, drawTestDepthGreater_, drawTestStencilAlwaysDepthGreater_ };
455 	const int numTests = ARRAY_SIZE(testNames);
456 
457 	static const bool validCombinations[numWriteModes][numTests] = {
458 		{true, true, true, true},
459 		{true, true, false, false},
460 		{false, false, true, true},
461 	};
462 
463 	// Don't want any fancy font texture stuff going on here, so use FLAG_DYNAMIC_ASCII everywhere!
464 
465 	// We draw the background at Z=0.5 and the text at Z=0.9.
466 
467 	// Then we draw a rectangle with a depth test or stencil test that should mask out the text.
468 	// Plus a second rectangle with the opposite test.
469 
470 	// If everything is OK, both the background and the text should be OK.
471 
472 	Bounds layoutBounds = dc.GetLayoutBounds();
473 
474 	dc.Begin();
475 	dc.SetFontScale(1.0f, 1.0f);
476 	std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME);
477 	std::string vendor = screenManager()->getDrawContext()->GetInfoString(InfoField::VENDORSTRING);
478 	std::string driver = screenManager()->getDrawContext()->GetInfoString(InfoField::DRIVER);
479 	dc.DrawText(apiName.c_str(), layoutBounds.centerX(), 20, 0xFFFFFFFF, ALIGN_CENTER);
480 	dc.DrawText(vendor.c_str(), layoutBounds.centerX(), 60, 0xFFFFFFFF, ALIGN_CENTER);
481 	dc.DrawText(driver.c_str(), layoutBounds.centerX(), 100, 0xFFFFFFFF, ALIGN_CENTER);
482 	dc.Flush();
483 
484 	float testW = 170.f;
485 	float padding = 20.0f;
486 	UI::Style style = dc.theme->itemStyle;
487 
488 	float y = 150;
489 	for (int j = 0; j < numWriteModes; j++, y += 120.f + padding) {
490 		float x = layoutBounds.x + (layoutBounds.w - (float)numTests * testW - (float)(numTests - 1) * padding) / 2.0f;
491 		dc.Begin();
492 		dc.DrawText(writeModeNames[j], layoutBounds.x + padding, y + 40, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
493 		dc.Flush();
494 		for (int i = 0; i < numTests; i++, x += testW + padding) {
495 			if (!validCombinations[j][i])
496 				continue;
497 			dc.Begin();
498 			Bounds bounds = { x, y + 40, testW, 70 };
499 			dc.DrawText(testNames[i], bounds.x, y, style.fgColor, FLAG_DYNAMIC_ASCII);
500 			dc.Flush();
501 
502 			dc.BeginPipeline(writePipelines[j], samplerNearest_);
503 			// Draw the rectangle with stencil value 0, depth 0.1f and the text with stencil 0xFF, depth 0.9. Then leave 0xFF as the stencil value and draw the rectangles at depth 0.5.
504 			draw->SetStencilRef(0x0);
505 			dc.SetCurZ(0.1f);
506 			dc.FillRect(UI::Drawable(bgColorBAD), bounds);
507 			// test bounds
508 			dc.Flush();
509 
510 			draw->SetStencilRef(0xff);
511 			dc.SetCurZ(0.9f);
512 			dc.DrawTextRect("TEST OK", bounds, textColorBAD, ALIGN_HCENTER | ALIGN_VCENTER | FLAG_DYNAMIC_ASCII);
513 			dc.Flush();
514 
515 			// Draw rectangle that should result in the text
516 			dc.BeginPipeline(testPipeline1[i], samplerNearest_);
517 			draw->SetStencilRef(0xff);
518 			dc.SetCurZ(0.5f);
519 			dc.FillRect(UI::Drawable(textColorOK), bounds);
520 			dc.Flush();
521 
522 			// Draw rectangle that should result in the bg
523 			dc.BeginPipeline(testPipeline2[i], samplerNearest_);
524 			draw->SetStencilRef(0xff);
525 			dc.SetCurZ(0.5f);
526 			dc.FillRect(UI::Drawable(bgColorOK), bounds);
527 			dc.Flush();
528 		}
529 	}
530 	dc.Flush();
531 }
532 
ShaderTest()533 void GPUDriverTestScreen::ShaderTest() {
534 	using namespace Draw;
535 
536 	UIContext &dc = *screenManager()->getUIContext();
537 	Draw::DrawContext *draw = dc.GetDrawContext();
538 
539 	if (!adrenoLogicDiscardPipeline_) {
540 		adrenoLogicDiscardFragShader_ = CreateShader(draw, ShaderStage::Fragment, fsAdrenoLogicTest);
541 		adrenoLogicDiscardVertShader_ = CreateShader(draw, ShaderStage::Vertex, vsAdrenoLogicTest);
542 
543 		flatFragShader_ = CreateShader(draw, ShaderStage::Fragment, fsFlat);
544 		flatVertShader_ = CreateShader(draw, ShaderStage::Vertex, vsFlat);
545 
546 		InputLayout *inputLayout = ui_draw2d.CreateInputLayout(draw);
547 		// No blending used.
548 		BlendState *blendOff = draw->CreateBlendState({ false, 0xF });
549 
550 		// No depth or stencil, we only use discard in this test.
551 		DepthStencilStateDesc dsDesc{};
552 		dsDesc.depthTestEnabled = false;
553 		dsDesc.depthWriteEnabled = false;
554 		DepthStencilState *depthStencilOff = draw->CreateDepthStencilState(dsDesc);
555 
556 		RasterState *rasterNoCull = draw->CreateRasterState({});
557 
558 		PipelineDesc adrenoLogicDiscardDesc{
559 			Primitive::TRIANGLE_LIST,
560 			{ adrenoLogicDiscardVertShader_, adrenoLogicDiscardFragShader_ },
561 			inputLayout, depthStencilOff, blendOff, rasterNoCull, &vsColBufDesc,
562 		};
563 		adrenoLogicDiscardPipeline_ = draw->CreateGraphicsPipeline(adrenoLogicDiscardDesc);
564 
565 		PipelineDesc flatDesc{
566 			Primitive::TRIANGLE_LIST,
567 			{ flatVertShader_, flatFragShader_ },
568 			inputLayout, depthStencilOff, blendOff, rasterNoCull, &vsColBufDesc,
569 		};
570 		flatShadingPipeline_ = draw->CreateGraphicsPipeline(flatDesc);
571 
572 		inputLayout->Release();
573 		blendOff->Release();
574 		depthStencilOff->Release();
575 		rasterNoCull->Release();
576 	}
577 
578 	Bounds layoutBounds = dc.GetLayoutBounds();
579 
580 	dc.Begin();
581 	dc.SetFontScale(1.0f, 1.0f);
582 	std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME);
583 	std::string vendor = screenManager()->getDrawContext()->GetInfoString(InfoField::VENDORSTRING);
584 	std::string driver = screenManager()->getDrawContext()->GetInfoString(InfoField::DRIVER);
585 	dc.DrawText(apiName.c_str(), layoutBounds.centerX(), 20, 0xFFFFFFFF, ALIGN_CENTER);
586 	dc.DrawText(vendor.c_str(), layoutBounds.centerX(), 60, 0xFFFFFFFF, ALIGN_CENTER);
587 	dc.DrawText(driver.c_str(), layoutBounds.centerX(), 100, 0xFFFFFFFF, ALIGN_CENTER);
588 	dc.Flush();
589 
590 	float y = layoutBounds.y + 150;
591 	float x = layoutBounds.x + 10;
592 	dc.Begin();
593 	dc.DrawText("Adreno logic", x, y, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
594 	dc.Flush();
595 
596 	float testW = 170.f;
597 
598 	Bounds bounds = { x + 200, y, testW, 70 };
599 
600 	// Draw rectangle that should result in the bg
601 	dc.Begin();
602 	dc.FillRect(UI::Drawable(bgColorOK), bounds);
603 	dc.Flush();
604 
605 	// Draw text on it using the shader.
606 	dc.BeginPipeline(adrenoLogicDiscardPipeline_, samplerNearest_);
607 	dc.DrawTextRect("TEST OK", bounds, textColorOK, ALIGN_HCENTER | ALIGN_VCENTER | FLAG_DYNAMIC_ASCII);
608 	dc.Flush();
609 
610 	y += 100;
611 
612 	dc.Begin();
613 	dc.DrawText("Flat shaded tex", x, y, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
614 	dc.DrawText("(TEST OK if logo but no gradient!)", x + 400, y, 0xFFFFFFFF, ALIGN_LEFT);
615 	dc.Flush();
616 
617 	bounds = { x + 200, y, 100, 100 };
618 
619 	// Draw rectangle that should be flat shaded
620 	dc.BeginPipeline(flatShadingPipeline_, samplerNearest_);
621 	// There is a "provoking vertex" difference here between GL and Vulkan when using flat shading. One gets one color, one gets the other.
622 	// Wherever possible we should reconfigure the GL provoking vertex to match Vulkan, probably.
623 	dc.DrawImageVGradient(ImageID("I_ICON"), 0xFFFFFFFF, 0xFF808080, bounds);
624 	dc.Flush();
625 
626 	y += 120;
627 
628 	dc.Begin();
629 	dc.DrawText("Test done", x, y, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
630 	dc.Flush();
631 }
632 
633 
render()634 void GPUDriverTestScreen::render() {
635 	using namespace Draw;
636 	UIScreen::render();
637 
638 	switch (tabHolder_->GetCurrentTab()) {
639 	case 0:
640 		DiscardTest();
641 		break;
642 	case 1:
643 		ShaderTest();
644 		break;
645 	}
646 }
647