blob: 6d88b23302798ad391a3c36e70fe2bc12b3de624 [file] [log] [blame]
Chris Forbesaab9d112015-04-02 13:22:31 +13001/*
2 * Vulkan
3 *
4 * Copyright (C) 2015 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24#include <string.h>
25#include <stdlib.h>
26#include <assert.h>
Chris Forbes67cc36f2015-04-13 12:14:52 +120027#include <map>
Chris Forbesaab9d112015-04-02 13:22:31 +130028#include <unordered_map>
Chris Forbes4396ff52015-04-08 10:11:59 +120029#include <vector>
Chris Forbesaab9d112015-04-02 13:22:31 +130030#include "loader_platform.h"
31#include "vk_dispatch_table_helper.h"
32#include "vkLayer.h"
33// The following is #included again to catch certain OS-specific functions
34// being used:
35#include "loader_platform.h"
36
37#include "SPIRV/spirv.h"
38
39static std::unordered_map<void *, VkLayerDispatchTable *> tableMap;
40
Chris Forbes4396ff52015-04-08 10:11:59 +120041
42struct shader_source {
43 std::vector<uint32_t> words;
44
45 shader_source(VkShaderCreateInfo const *pCreateInfo) :
46 words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)) {
47 }
48};
49
50
51static std::unordered_map<void *, shader_source *> shader_map;
52
53
Chris Forbesaab9d112015-04-02 13:22:31 +130054static VkLayerDispatchTable * initLayerTable(const VkBaseLayerObject *gpuw)
55{
56 VkLayerDispatchTable *pTable;
57
58 assert(gpuw);
59 std::unordered_map<void *, VkLayerDispatchTable *>::const_iterator it = tableMap.find((void *) gpuw->baseObject);
60 if (it == tableMap.end())
61 {
62 pTable = new VkLayerDispatchTable;
63 tableMap[(void *) gpuw->baseObject] = pTable;
64 } else
65 {
66 return it->second;
67 }
68
69 layer_initialize_dispatch_table(pTable, gpuw->pGPA, (VkPhysicalGpu) gpuw->nextObject);
70
71 return pTable;
72}
73
74
75VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalGpu gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
76{
77 VkLayerDispatchTable* pTable = tableMap[gpu];
78 VkResult result = pTable->CreateDevice(gpu, pCreateInfo, pDevice);
79 // create a mapping for the device object into the dispatch table
80 tableMap.emplace(*pDevice, pTable);
81 return result;
82}
83
84
85VK_LAYER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
86{
87 if (pOutLayerCount == NULL || pOutLayers == NULL || pOutLayers[0] == NULL || pOutLayers[1] == NULL || pReserved == NULL)
88 return VK_ERROR_INVALID_POINTER;
89
90 if (maxLayerCount < 1)
91 return VK_ERROR_INITIALIZATION_FAILED;
92 *pOutLayerCount = 1;
93 strncpy((char *) pOutLayers[0], "ShaderChecker", maxStringSize);
94 return VK_SUCCESS;
95}
96
97
98struct extProps {
99 uint32_t version;
100 const char * const name;
101};
102#define SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE 1
103static const struct extProps shaderCheckerExts[SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE] = {
104 // TODO what is the version?
105 0x10, "ShaderChecker",
106};
107
108
109VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
110 VkExtensionInfoType infoType,
111 uint32_t extensionIndex,
112 size_t* pDataSize,
113 void* pData)
114{
115 VkResult result;
116
117 /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
118 VkExtensionProperties *ext_props;
119 uint32_t *count;
120
121 if (pDataSize == NULL)
122 return VK_ERROR_INVALID_POINTER;
123
124 switch (infoType) {
125 case VK_EXTENSION_INFO_TYPE_COUNT:
126 *pDataSize = sizeof(uint32_t);
127 if (pData == NULL)
128 return VK_SUCCESS;
129 count = (uint32_t *) pData;
130 *count = SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE;
131 break;
132 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
133 *pDataSize = sizeof(VkExtensionProperties);
134 if (pData == NULL)
135 return VK_SUCCESS;
136 if (extensionIndex >= SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE)
137 return VK_ERROR_INVALID_VALUE;
138 ext_props = (VkExtensionProperties *) pData;
139 ext_props->version = shaderCheckerExts[extensionIndex].version;
140 strncpy(ext_props->extName, shaderCheckerExts[extensionIndex].name,
141 VK_MAX_EXTENSION_NAME);
142 ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
143 break;
144 default:
145 return VK_ERROR_INVALID_VALUE;
146 };
147
148 return VK_SUCCESS;
149}
150
151
Chris Forbes67cc36f2015-04-13 12:14:52 +1200152static int
153value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def)
154{
155 auto it = map.find(id);
156 if (it == map.end())
157 return def;
158 else
159 return it->second;
160}
161
162
163struct interface_var {
164 uint32_t id;
165 uint32_t type_id;
166 /* TODO: collect the name, too? Isn't required to be present. */
167};
168
169
170static void
171collect_interface_by_location(shader_source const *src, spv::StorageClass interface,
172 std::map<uint32_t, interface_var> &out,
173 std::map<uint32_t, interface_var> &builtins_out)
174{
175 unsigned int const *code = (unsigned int const *)&src->words[0];
176 size_t size = src->words.size();
177
178 if (code[0] != spv::MagicNumber) {
179 printf("Invalid magic.\n");
180 return;
181 }
182
183 std::unordered_map<unsigned, unsigned> var_locations;
184 std::unordered_map<unsigned, unsigned> var_builtins;
185
186 unsigned word = 5;
187 while (word < size) {
188
189 unsigned opcode = code[word] & 0x0ffffu;
190 unsigned oplen = (code[word] & 0xffff0000u) >> 16;
191
192 /* We consider two interface models: SSO rendezvous-by-location, and
193 * builtins. Complain about anything that fits neither model.
194 */
195 if (opcode == spv::OpDecorate) {
196 if (code[word+2] == spv::DecLocation) {
197 var_locations[code[word+1]] = code[word+3];
198 }
199
200 if (code[word+2] == spv::DecBuiltIn) {
201 var_builtins[code[word+1]] = code[word+3];
202 }
203 }
204
205 /* TODO: handle grouped decorations */
206 /* TODO: handle index=1 dual source outputs from FS -- two vars will
207 * have the same location, and we DONT want to clobber. */
208
209 if (opcode == spv::OpVariable && code[word+3] == interface) {
210 int location = value_or_default(var_locations, code[word+2], -1);
211 int builtin = value_or_default(var_builtins, code[word+2], -1);
212
213 if (location == -1 && builtin == -1) {
214 /* No location defined, and not bound to an API builtin.
215 * The spec says nothing about how this case works (or doesn't)
216 * for interface matching.
217 */
218 printf("WARN: var %d (type %d) in %s interface has no Location or Builtin decoration\n",
219 code[word+2], code[word+1], interface == spv::StorageInput ? "input" : "output");
220 }
221 else if (location != -1) {
222 /* A user-defined interface variable, with a location. */
223 interface_var v;
224 v.id = code[word+2];
225 v.type_id = code[word+1];
226 out[location] = v;
227 }
228 else {
229 /* A builtin interface variable */
230 interface_var v;
231 v.id = code[word+2];
232 v.type_id = code[word+1];
233 builtins_out[builtin] = v;
234 }
235 }
236
237 word += oplen;
238 }
239}
240
241
Chris Forbesaab9d112015-04-02 13:22:31 +1300242VK_LAYER_EXPORT VkResult VKAPI vkCreateShader(VkDevice device, const VkShaderCreateInfo *pCreateInfo,
243 VkShader *pShader)
244{
245 VkLayerDispatchTable* pTable = tableMap[(VkBaseLayerObject *)device];
246 VkResult res = pTable->CreateShader(device, pCreateInfo, pShader);
Chris Forbes4396ff52015-04-08 10:11:59 +1200247
248 shader_map[(VkBaseLayerObject *) *pShader] = new shader_source(pCreateInfo);
Chris Forbesaab9d112015-04-02 13:22:31 +1300249 return res;
250}
251
252
Chris Forbes60540932015-04-08 10:15:35 +1200253VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipeline(VkDevice device,
254 const VkGraphicsPipelineCreateInfo *pCreateInfo,
255 VkPipeline *pPipeline)
256{
257 /* TODO: run cross-stage validation */
258 /* - Validate vertex fetch -> VS interface */
259 /* - Validate FS output -> CB */
260 /* - Support GS, TCS, TES stages */
261
Chris Forbes8f600932015-04-08 10:16:45 +1200262 /* We seem to allow pipeline stages to be specified out of order, so collect and identify them
263 * before trying to do anything more: */
264
265 shader_source const *vs_source = 0;
266 shader_source const *fs_source = 0;
267 VkPipelineCbStateCreateInfo const *cb = 0;
268 VkPipelineVertexInputCreateInfo const *vi = 0;
269
270 for (auto stage = pCreateInfo; stage; stage = (decltype(stage))stage->pNext) {
271 if (stage->sType == VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) {
272 auto shader_stage = (VkPipelineShaderStageCreateInfo const *)stage;
273
274 if (shader_stage->shader.stage == VK_SHADER_STAGE_VERTEX)
275 vs_source = shader_map[(void *)(shader_stage->shader.shader)];
276 else if (shader_stage->shader.stage == VK_SHADER_STAGE_FRAGMENT)
277 fs_source = shader_map[(void *)(shader_stage->shader.shader)];
278 else
279 printf("Unknown shader stage %d\n", shader_stage->shader.stage);
280 }
281 else if (stage->sType == VK_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO) {
282 cb = (VkPipelineCbStateCreateInfo const *)stage;
283 }
284 else if (stage->sType == VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO) {
285 vi = (VkPipelineVertexInputCreateInfo const *)stage;
286 }
287 }
288
289 printf("Pipeline: vi=%p vs=%p fs=%p cb=%p\n", vi, vs_source, fs_source, cb);
290
Chris Forbes60540932015-04-08 10:15:35 +1200291 VkLayerDispatchTable *pTable = tableMap[(VkBaseLayerObject *)device];
292 VkResult res = pTable->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
293 return res;
294}
295
296
Chris Forbesaab9d112015-04-02 13:22:31 +1300297VK_LAYER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char* pName)
298{
299 if (gpu == NULL)
300 return NULL;
301
302 initLayerTable((const VkBaseLayerObject *) gpu);
303
304#define ADD_HOOK(fn) \
305 if (!strncmp(#fn, pName, sizeof(#fn))) \
306 return (void *) fn
307
308 ADD_HOOK(vkGetProcAddr);
309 ADD_HOOK(vkEnumerateLayers);
310 ADD_HOOK(vkCreateDevice);
311 ADD_HOOK(vkCreateShader);
Chris Forbes60540932015-04-08 10:15:35 +1200312 ADD_HOOK(vkCreateGraphicsPipeline);
Chris Forbesaab9d112015-04-02 13:22:31 +1300313
314 VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu;
315 if (gpuw->pGPA == NULL)
316 return NULL;
317 return gpuw->pGPA((VkPhysicalGpu) gpuw->nextObject, pName);
318}