1from .common.codegen import CodeGen, VulkanWrapperGenerator, VulkanAPIWrapper 2from .common.vulkantypes import \ 3 VulkanAPI, makeVulkanTypeSimple, iterateVulkanType, DISPATCHABLE_HANDLE_TYPES, NON_DISPATCHABLE_HANDLE_TYPES 4 5from .reservedmarshaling import VulkanReservedMarshalingCodegen 6from .transform import TransformCodegen, genTransformsForVulkanType 7 8from .wrapperdefs import API_PREFIX_MARSHAL 9from .wrapperdefs import API_PREFIX_UNMARSHAL, API_PREFIX_RESERVEDUNMARSHAL 10from .wrapperdefs import ROOT_TYPE_DEFAULT_VALUE 11from .wrapperdefs import VULKAN_STREAM_TYPE 12 13from copy import copy 14 15decoder_decl_preamble = """ 16""" 17 18decoder_impl_preamble = """ 19""" 20 21READ_STREAM = "readStream" 22WRITE_STREAM = "vkStream" 23 24# Driver workarounds for APIs that don't work well multithreaded 25driver_workarounds_global_lock_apis = [ 26 "vkCreatePipelineLayout", 27 "vkDestroyPipelineLayout", 28] 29 30MAX_STACK_ITEMS = "16" 31 32 33def emit_param_decl_for_reading(param, cgen): 34 if param.staticArrExpr: 35 cgen.stmt( 36 cgen.makeRichCTypeDecl(param.getForNonConstAccess())) 37 else: 38 cgen.stmt( 39 cgen.makeRichCTypeDecl(param)) 40 41 if param.pointerIndirectionLevels > 0: 42 lenAccess = cgen.generalLengthAccess(param) 43 if not lenAccess: 44 lenAccess = "1" 45 arrSize = "1" if "1" == lenAccess else "MAX_STACK_ITEMS" 46 47 typeHere = "uint8_t*" if "void" == param.typeName else param.typeName 48 cgen.stmt("%s%s stack_%s[%s]" % ( 49 typeHere, "*" * (param.pointerIndirectionLevels - 1), param.paramName, arrSize)) 50 51 52def emit_unmarshal(typeInfo, param, cgen, output=False, destroy=False, noUnbox=False): 53 if destroy: 54 iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen( 55 cgen, 56 READ_STREAM, 57 ROOT_TYPE_DEFAULT_VALUE, 58 param.paramName, 59 "readStreamPtrPtr", 60 API_PREFIX_RESERVEDUNMARSHAL, 61 "", 62 direction="read", 63 dynAlloc=True)) 64 lenAccess = cgen.generalLengthAccess(param) 65 lenAccessGuard = cgen.generalLengthAccessGuard(param) 66 if None == lenAccess or "1" == lenAccess: 67 cgen.stmt("boxed_%s_preserve = %s" % 68 (param.paramName, param.paramName)) 69 cgen.stmt("%s = unbox_%s(%s)" % 70 (param.paramName, param.typeName, param.paramName)) 71 else: 72 if lenAccessGuard is not None: 73 self.cgen.beginIf(lenAccessGuard) 74 cgen.beginFor("uint32_t i = 0", "i < %s" % lenAccess, "++i") 75 cgen.stmt("boxed_%s_preserve[i] = %s[i]" % 76 (param.paramName, param.paramName)) 77 cgen.stmt("((%s*)(%s))[i] = unbox_%s(%s[i])" % (param.typeName, 78 param.paramName, param.typeName, param.paramName)) 79 cgen.endFor() 80 if lenAccessGuard is not None: 81 self.cgen.endIf() 82 else: 83 if noUnbox: 84 cgen.line("// No unbox for %s" % (param.paramName)) 85 86 lenAccess = cgen.generalLengthAccess(param) 87 if not lenAccess: 88 lenAccess = "1" 89 arrSize = "1" if "1" == lenAccess else "MAX_STACK_ITEMS" 90 91 iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen( 92 cgen, 93 READ_STREAM, 94 ROOT_TYPE_DEFAULT_VALUE, 95 param.paramName, 96 "readStreamPtrPtr", 97 API_PREFIX_RESERVEDUNMARSHAL, 98 "" if (output or noUnbox) else "unbox_", 99 direction="read", 100 dynAlloc=True, 101 stackVar="stack_%s" % param.paramName, 102 stackArrSize=arrSize)) 103 104 105def emit_dispatch_unmarshal(typeInfo, param, cgen, globalWrapped): 106 if globalWrapped: 107 cgen.stmt( 108 "// Begin global wrapped dispatchable handle unboxing for %s" % param.paramName) 109 iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen( 110 cgen, 111 READ_STREAM, 112 ROOT_TYPE_DEFAULT_VALUE, 113 param.paramName, 114 "readStreamPtrPtr", 115 API_PREFIX_RESERVEDUNMARSHAL, 116 "", 117 direction="read", 118 dynAlloc=True)) 119 else: 120 cgen.stmt( 121 "// Begin non wrapped dispatchable handle unboxing for %s" % param.paramName) 122 # cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM) 123 iterateVulkanType(typeInfo, param, VulkanReservedMarshalingCodegen( 124 cgen, 125 READ_STREAM, 126 ROOT_TYPE_DEFAULT_VALUE, 127 param.paramName, 128 "readStreamPtrPtr", 129 API_PREFIX_RESERVEDUNMARSHAL, 130 "", 131 direction="read", 132 dynAlloc=True)) 133 cgen.stmt("auto unboxed_%s = unbox_%s(%s)" % 134 (param.paramName, param.typeName, param.paramName)) 135 cgen.stmt("auto vk = dispatch_%s(%s)" % 136 (param.typeName, param.paramName)) 137 cgen.stmt("// End manual dispatchable handle unboxing for %s" % 138 param.paramName) 139 140 141def emit_transform(typeInfo, param, cgen, variant="tohost"): 142 res = \ 143 iterateVulkanType(typeInfo, param, TransformCodegen( 144 cgen, param.paramName, "globalstate", "transform_%s_" % variant, variant)) 145 if not res: 146 cgen.stmt("(void)%s" % param.paramName) 147 148# Everything here elides the initial arg 149 150 151class DecodingParameters(object): 152 def __init__(self, api): 153 self.params = [] 154 self.toRead = [] 155 self.toWrite = [] 156 157 i = 0 158 159 for param in api.parameters[1:]: 160 param.nonDispatchableHandleCreate = False 161 param.nonDispatchableHandleDestroy = False 162 param.dispatchHandle = False 163 param.dispatchableHandleCreate = False 164 param.dispatchableHandleDestroy = False 165 166 if i == 0 and param.isDispatchableHandleType(): 167 param.dispatchHandle = True 168 169 if param.isNonDispatchableHandleType() and param.isCreatedBy(api): 170 param.nonDispatchableHandleCreate = True 171 172 if param.isNonDispatchableHandleType() and param.isDestroyedBy(api): 173 param.nonDispatchableHandleDestroy = True 174 175 if param.isDispatchableHandleType() and param.isCreatedBy(api): 176 param.dispatchableHandleCreate = True 177 178 if param.isDispatchableHandleType() and param.isDestroyedBy(api): 179 param.dispatchableHandleDestroy = True 180 181 self.toRead.append(param) 182 183 if param.possiblyOutput(): 184 self.toWrite.append(param) 185 186 self.params.append(param) 187 188 i += 1 189 190 191def emit_call_log(api, cgen): 192 decodingParams = DecodingParameters(api) 193 paramsToRead = decodingParams.toRead 194 195 # cgen.beginIf("m_logCalls") 196 paramLogFormat = "%p" 197 paramLogArgs = ["(void*)boxed_dispatchHandle"] 198 199 for p in paramsToRead: 200 paramLogFormat += "0x%llx " 201 for p in paramsToRead: 202 paramLogArgs.append("(unsigned long long)%s" % (p.paramName)) 203 # cgen.stmt("fprintf(stderr, \"substream %%p: call %s %s\\n\", readStream, %s)" % (api.name, paramLogFormat, ", ".join(paramLogArgs))) 204 # cgen.endIf() 205 206 207def emit_decode_parameters(typeInfo, api, cgen, globalWrapped=False): 208 209 decodingParams = DecodingParameters(api) 210 211 paramsToRead = decodingParams.toRead 212 213 for p in paramsToRead: 214 emit_param_decl_for_reading(p, cgen) 215 216 i = 0 217 for p in paramsToRead: 218 lenAccess = cgen.generalLengthAccess(p) 219 220 if p.dispatchHandle: 221 emit_dispatch_unmarshal(typeInfo, p, cgen, globalWrapped) 222 else: 223 destroy = p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy 224 noUnbox = False 225 226 if p.nonDispatchableHandleDestroy or p.dispatchableHandleDestroy: 227 destroy = True 228 cgen.stmt( 229 "// Begin manual non dispatchable handle destroy unboxing for %s" % p.paramName) 230 if None == lenAccess or "1" == lenAccess: 231 cgen.stmt("%s boxed_%s_preserve" % 232 (p.typeName, p.paramName)) 233 else: 234 cgen.stmt("%s* boxed_%s_preserve; %s->alloc((void**)&boxed_%s_preserve, %s * sizeof(%s))" % 235 (p.typeName, p.paramName, READ_STREAM, p.paramName, lenAccess, p.typeName)) 236 237 if p.possiblyOutput(): 238 cgen.stmt( 239 "// Begin manual dispatchable handle unboxing for %s" % p.paramName) 240 cgen.stmt("%s->unsetHandleMapping()" % READ_STREAM) 241 242 emit_unmarshal(typeInfo, p, cgen, output=p.possiblyOutput( 243 ), destroy=destroy, noUnbox=noUnbox) 244 i += 1 245 246 for p in paramsToRead: 247 emit_transform(typeInfo, p, cgen, variant="tohost") 248 249 emit_call_log(api, cgen) 250 251 252def emit_dispatch_call(api, cgen): 253 254 decodingParams = DecodingParameters(api) 255 256 customParams = ["(VkCommandBuffer)dispatchHandle"] 257 258 for (i, p) in enumerate(api.parameters[1:]): 259 customParam = p.paramName 260 if decodingParams.params[i].dispatchHandle: 261 customParam = "unboxed_%s" % p.paramName 262 customParams.append(customParam) 263 264 if api.name in driver_workarounds_global_lock_apis: 265 cgen.stmt("lock()") 266 267 cgen.vkApiCall(api, customPrefix="vk->", customParameters=customParams) 268 269 if api.name in driver_workarounds_global_lock_apis: 270 cgen.stmt("unlock()") 271 272 273def emit_global_state_wrapped_call(api, cgen): 274 customParams = ["pool", "(VkCommandBuffer)(boxed_dispatchHandle)"] + \ 275 list(map(lambda p: p.paramName, api.parameters[1:])) 276 cgen.vkApiCall(api, customPrefix="this->on_", 277 customParameters=customParams) 278 279 280def emit_default_decoding(typeInfo, api, cgen): 281 emit_decode_parameters(typeInfo, api, cgen) 282 emit_dispatch_call(api, cgen) 283 284 285def emit_global_state_wrapped_decoding(typeInfo, api, cgen): 286 emit_decode_parameters(typeInfo, api, cgen, globalWrapped=True) 287 emit_global_state_wrapped_call(api, cgen) 288 289 290custom_decodes = { 291 "vkCmdCopyBufferToImage": emit_global_state_wrapped_decoding, 292 "vkCmdCopyImage": emit_global_state_wrapped_decoding, 293 "vkCmdCopyImageToBuffer": emit_global_state_wrapped_decoding, 294 "vkCmdExecuteCommands": emit_global_state_wrapped_decoding, 295 "vkBeginCommandBuffer": emit_global_state_wrapped_decoding, 296 "vkResetCommandBuffer": emit_global_state_wrapped_decoding, 297 "vkCmdPipelineBarrier": emit_global_state_wrapped_decoding, 298 "vkCmdBindPipeline": emit_global_state_wrapped_decoding, 299 "vkCmdBindDescriptorSets": emit_global_state_wrapped_decoding, 300 "vkBeginCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding, 301 "vkEndCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding, 302 "vkResetCommandBufferAsyncGOOGLE": emit_global_state_wrapped_decoding, 303 "vkCommandBufferHostSyncGOOGLE": emit_global_state_wrapped_decoding, 304} 305 306 307class VulkanSubDecoder(VulkanWrapperGenerator): 308 def __init__(self, module, typeInfo): 309 VulkanWrapperGenerator.__init__(self, module, typeInfo) 310 self.typeInfo = typeInfo 311 self.cgen = CodeGen() 312 313 def onBegin(self,): 314 self.module.appendImpl( 315 "#define MAX_STACK_ITEMS %s\n" % MAX_STACK_ITEMS) 316 317 self.module.appendImpl( 318 "size_t subDecode(VulkanMemReadingStream* readStream, VulkanDispatch* vk, void* boxed_dispatchHandle, void* dispatchHandle, VkDeviceSize dataSize, const void* pData)\n") 319 320 self.cgen.beginBlock() # function body 321 322 self.cgen.stmt("uint32_t count = 0") 323 self.cgen.stmt("unsigned char *buf = (unsigned char *)pData") 324 self.cgen.stmt("android::base::BumpPool* pool = readStream->pool()") 325 self.cgen.stmt("unsigned char *ptr = (unsigned char *)pData") 326 self.cgen.stmt( 327 "const unsigned char* const end = (const unsigned char*)buf + dataSize") 328 self.cgen.stmt( 329 "VkDecoderGlobalState* globalstate = VkDecoderGlobalState::get()") 330 331 self.cgen.line("while (end - ptr >= 8)") 332 self.cgen.beginBlock() # while loop 333 334 self.cgen.stmt("uint32_t opcode = *(uint32_t *)ptr") 335 self.cgen.stmt("int32_t packetLen = *(int32_t *)(ptr + 4)") 336 self.cgen.stmt( 337 "if (end - ptr < packetLen) return ptr - (unsigned char*)buf") 338 339 self.cgen.stmt("%s->setBuf((uint8_t*)(ptr + 8))" % READ_STREAM) 340 self.cgen.stmt( 341 "uint8_t* readStreamPtr = %s->getBuf(); uint8_t** readStreamPtrPtr = &readStreamPtr" % READ_STREAM) 342 self.cgen.line("switch (opcode)") 343 self.cgen.beginBlock() # switch stmt 344 345 self.module.appendImpl(self.cgen.swapCode()) 346 347 def onGenCmd(self, cmdinfo, name, alias): 348 typeInfo = self.typeInfo 349 cgen = self.cgen 350 api = typeInfo.apis[name] 351 352 if "commandBuffer" != api.parameters[0].paramName: 353 return 354 355 cgen.line("case OP_%s:" % name) 356 cgen.beginBlock() 357 cgen.stmt("android::base::beginTrace(\"%s subdecode\")" % name) 358 359 if api.name in custom_decodes.keys(): 360 custom_decodes[api.name](typeInfo, api, cgen) 361 else: 362 emit_default_decoding(typeInfo, api, cgen) 363 364 cgen.stmt("android::base::endTrace()") 365 cgen.stmt("break") 366 cgen.endBlock() 367 self.module.appendImpl(self.cgen.swapCode()) 368 369 def onEnd(self,): 370 self.cgen.line("default:") 371 self.cgen.beginBlock() 372 self.cgen.stmt( 373 "fprintf(stderr, \"Fatal, unrecognized opcode %u\\n\", opcode)") 374 self.cgen.stmt("abort()") 375 self.cgen.stmt("return ptr - (unsigned char *)buf") 376 self.cgen.endBlock() 377 378 self.cgen.endBlock() # switch stmt 379 380 self.cgen.stmt("++count; if (count % 1000 == 0) { pool->freeAll(); }") 381 self.cgen.stmt("ptr += packetLen") 382 self.cgen.endBlock() # while loop 383 384 self.cgen.stmt("pool->freeAll()") 385 self.cgen.stmt("return ptr - (unsigned char*)buf;") 386 self.cgen.endBlock() # function body 387 self.module.appendImpl(self.cgen.swapCode()) 388