summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/render/bgfx/shadermanager.cpp
blob: 282029cb96ab373aefdb753089550eaa1e9316c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
//============================================================
//
//  shadermanager.cpp - BGFX shader manager
//
//  Maintains a mapping between strings and BGFX shaders,
//  either vertex or pixel/fragment.
//
//============================================================

#include "shadermanager.h"

#include "emucore.h"

#include "osdfile.h"
#include "modules/lib/osdobj_common.h"

#include <bx/file.h>
#include <bx/math.h>
#include <bx/readerwriter.h>


shader_manager::~shader_manager()
{
	for (std::pair<std::string, bgfx::ShaderHandle> shader : m_shaders)
	{
		bgfx::destroy(shader.second);
	}
	m_shaders.clear();
}

bgfx::ShaderHandle shader_manager::get_or_load_shader(const osd_options &options, const std::string &name)
{
	std::map<std::string, bgfx::ShaderHandle>::iterator iter = m_shaders.find(name);
	if (iter != m_shaders.end())
	{
		return iter->second;
	}

	bgfx::ShaderHandle handle = load_shader(options, name);
	if (handle.idx != bgfx::kInvalidHandle)
	{
		m_shaders[name] = handle;
	}

	return handle;
}

bgfx::ShaderHandle shader_manager::load_shader(const osd_options &options, const std::string &name)
{
	std::string shader_path = make_path_string(options, name);
	const bgfx::Memory* mem = load_mem(shader_path + name + ".bin");
	if (mem != nullptr)
	{
		return bgfx::createShader(mem);
	}

	return BGFX_INVALID_HANDLE;
}

bool shader_manager::is_shader_present(const osd_options &options, const std::string &name)
{
	std::string shader_path = make_path_string(options, name);
	std::string file_name = shader_path + name + ".bin";
	bx::FileReader reader;
	bx::ErrorAssert err;
	if (bx::open(&reader, file_name.c_str()))
	{
		uint32_t expected_size(bx::getSize(&reader));
		uint8_t *data = new uint8_t[expected_size];
		uint32_t read_size = (uint32_t)bx::read(&reader, data, expected_size, &err);
		delete [] data;
		bx::close(&reader);

		return expected_size == read_size;
	}

	return false;
}

std::string shader_manager::make_path_string(const osd_options &options, const std::string &name)
{
	std::string shader_path(options.bgfx_path());
	shader_path += PATH_SEPARATOR "shaders" PATH_SEPARATOR;

#if defined(SDLMAME_EMSCRIPTEN)
	// Hard-code renderer type to OpenGL ES for emscripten builds since the
	// bgfx::getRendererType() is called here before BGFX has been
	// initialized and therefore gives the wrong renderer type (Noop).
	shader_path += "essl" PATH_SEPARATOR;
	return shader_path;
#endif

	switch (bgfx::getRendererType())
	{
		case bgfx::RendererType::Noop:
		case bgfx::RendererType::Direct3D9:
			shader_path += "dx9";
			break;

		case bgfx::RendererType::Direct3D11:
		case bgfx::RendererType::Direct3D12:
			shader_path += "dx11";
			break;

		case bgfx::RendererType::Gnm:
			shader_path += "pssl";
			break;

		case bgfx::RendererType::Metal:
			shader_path += "metal";
			break;

		case bgfx::RendererType::OpenGL:
			shader_path += "glsl";
			break;

		case bgfx::RendererType::OpenGLES:
			shader_path += "essl";
			break;

		case bgfx::RendererType::Vulkan:
			shader_path += "spirv";
			break;

		default:
			fatalerror("Unknown BGFX renderer type %d", bgfx::getRendererType());
	}
	shader_path += PATH_SEPARATOR;
	return shader_path;
}

const bgfx::Memory* shader_manager::load_mem(const std::string &name)
{
	bx::FileReader reader;
	if (bx::open(&reader, name.c_str()))
	{
		bx::ErrorAssert err;
		uint32_t size(bx::getSize(&reader));
		const bgfx::Memory* mem = bgfx::alloc(size + 1);
		bx::read(&reader, mem->data, size, &err);
		bx::close(&reader);

		mem->data[mem->size - 1] = '\0';
		return mem;
	}
	else
	{
		osd_printf_error("Unable to load shader %s\n", name);
	}
	return nullptr;
}