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