1*b7893ccfSSadaf Ebrahimi#!/usr/bin/python3 -i 2*b7893ccfSSadaf Ebrahimi# 3*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 The Khronos Group Inc. 4*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 Valve Corporation 5*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 LunarG, Inc. 6*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 Google Inc. 7*b7893ccfSSadaf Ebrahimi# 8*b7893ccfSSadaf Ebrahimi# Licensed under the Apache License, Version 2.0 (the "License"); 9*b7893ccfSSadaf Ebrahimi# you may not use this file except in compliance with the License. 10*b7893ccfSSadaf Ebrahimi# You may obtain a copy of the License at 11*b7893ccfSSadaf Ebrahimi# 12*b7893ccfSSadaf Ebrahimi# http://www.apache.org/licenses/LICENSE-2.0 13*b7893ccfSSadaf Ebrahimi# 14*b7893ccfSSadaf Ebrahimi# Unless required by applicable law or agreed to in writing, software 15*b7893ccfSSadaf Ebrahimi# distributed under the License is distributed on an "AS IS" BASIS, 16*b7893ccfSSadaf Ebrahimi# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17*b7893ccfSSadaf Ebrahimi# See the License for the specific language governing permissions and 18*b7893ccfSSadaf Ebrahimi# limitations under the License. 19*b7893ccfSSadaf Ebrahimi# 20*b7893ccfSSadaf Ebrahimi# Author: Mike Stroyan <[email protected]> 21*b7893ccfSSadaf Ebrahimi# Author: Mark Lobodzinski <[email protected]> 22*b7893ccfSSadaf Ebrahimi 23*b7893ccfSSadaf Ebrahimiimport os,re,sys 24*b7893ccfSSadaf Ebrahimifrom generator import * 25*b7893ccfSSadaf Ebrahimifrom common_codegen import * 26*b7893ccfSSadaf Ebrahimi 27*b7893ccfSSadaf Ebrahimi# ThreadGeneratorOptions - subclass of GeneratorOptions. 28*b7893ccfSSadaf Ebrahimi# 29*b7893ccfSSadaf Ebrahimi# Adds options used by ThreadOutputGenerator objects during threading 30*b7893ccfSSadaf Ebrahimi# layer generation. 31*b7893ccfSSadaf Ebrahimi# 32*b7893ccfSSadaf Ebrahimi# Additional members 33*b7893ccfSSadaf Ebrahimi# prefixText - list of strings to prefix generated header with 34*b7893ccfSSadaf Ebrahimi# (usually a copyright statement + calling convention macros). 35*b7893ccfSSadaf Ebrahimi# protectFile - True if multiple inclusion protection should be 36*b7893ccfSSadaf Ebrahimi# generated (based on the filename) around the entire header. 37*b7893ccfSSadaf Ebrahimi# protectFeature - True if #ifndef..#endif protection should be 38*b7893ccfSSadaf Ebrahimi# generated around a feature interface in the header file. 39*b7893ccfSSadaf Ebrahimi# genFuncPointers - True if function pointer typedefs should be 40*b7893ccfSSadaf Ebrahimi# generated 41*b7893ccfSSadaf Ebrahimi# protectProto - If conditional protection should be generated 42*b7893ccfSSadaf Ebrahimi# around prototype declarations, set to either '#ifdef' 43*b7893ccfSSadaf Ebrahimi# to require opt-in (#ifdef protectProtoStr) or '#ifndef' 44*b7893ccfSSadaf Ebrahimi# to require opt-out (#ifndef protectProtoStr). Otherwise 45*b7893ccfSSadaf Ebrahimi# set to None. 46*b7893ccfSSadaf Ebrahimi# protectProtoStr - #ifdef/#ifndef symbol to use around prototype 47*b7893ccfSSadaf Ebrahimi# declarations, if protectProto is set 48*b7893ccfSSadaf Ebrahimi# apicall - string to use for the function declaration prefix, 49*b7893ccfSSadaf Ebrahimi# such as APICALL on Windows. 50*b7893ccfSSadaf Ebrahimi# apientry - string to use for the calling convention macro, 51*b7893ccfSSadaf Ebrahimi# in typedefs, such as APIENTRY. 52*b7893ccfSSadaf Ebrahimi# apientryp - string to use for the calling convention macro 53*b7893ccfSSadaf Ebrahimi# in function pointer typedefs, such as APIENTRYP. 54*b7893ccfSSadaf Ebrahimi# indentFuncProto - True if prototype declarations should put each 55*b7893ccfSSadaf Ebrahimi# parameter on a separate line 56*b7893ccfSSadaf Ebrahimi# indentFuncPointer - True if typedefed function pointers should put each 57*b7893ccfSSadaf Ebrahimi# parameter on a separate line 58*b7893ccfSSadaf Ebrahimi# alignFuncParam - if nonzero and parameters are being put on a 59*b7893ccfSSadaf Ebrahimi# separate line, align parameter names at the specified column 60*b7893ccfSSadaf Ebrahimiclass ThreadGeneratorOptions(GeneratorOptions): 61*b7893ccfSSadaf Ebrahimi def __init__(self, 62*b7893ccfSSadaf Ebrahimi conventions = None, 63*b7893ccfSSadaf Ebrahimi filename = None, 64*b7893ccfSSadaf Ebrahimi directory = '.', 65*b7893ccfSSadaf Ebrahimi apiname = None, 66*b7893ccfSSadaf Ebrahimi profile = None, 67*b7893ccfSSadaf Ebrahimi versions = '.*', 68*b7893ccfSSadaf Ebrahimi emitversions = '.*', 69*b7893ccfSSadaf Ebrahimi defaultExtensions = None, 70*b7893ccfSSadaf Ebrahimi addExtensions = None, 71*b7893ccfSSadaf Ebrahimi removeExtensions = None, 72*b7893ccfSSadaf Ebrahimi emitExtensions = None, 73*b7893ccfSSadaf Ebrahimi sortProcedure = regSortFeatures, 74*b7893ccfSSadaf Ebrahimi prefixText = "", 75*b7893ccfSSadaf Ebrahimi genFuncPointers = True, 76*b7893ccfSSadaf Ebrahimi protectFile = True, 77*b7893ccfSSadaf Ebrahimi protectFeature = True, 78*b7893ccfSSadaf Ebrahimi apicall = '', 79*b7893ccfSSadaf Ebrahimi apientry = '', 80*b7893ccfSSadaf Ebrahimi apientryp = '', 81*b7893ccfSSadaf Ebrahimi indentFuncProto = True, 82*b7893ccfSSadaf Ebrahimi indentFuncPointer = False, 83*b7893ccfSSadaf Ebrahimi alignFuncParam = 0, 84*b7893ccfSSadaf Ebrahimi expandEnumerants = True): 85*b7893ccfSSadaf Ebrahimi GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile, 86*b7893ccfSSadaf Ebrahimi versions, emitversions, defaultExtensions, 87*b7893ccfSSadaf Ebrahimi addExtensions, removeExtensions, emitExtensions, sortProcedure) 88*b7893ccfSSadaf Ebrahimi self.prefixText = prefixText 89*b7893ccfSSadaf Ebrahimi self.genFuncPointers = genFuncPointers 90*b7893ccfSSadaf Ebrahimi self.protectFile = protectFile 91*b7893ccfSSadaf Ebrahimi self.protectFeature = protectFeature 92*b7893ccfSSadaf Ebrahimi self.apicall = apicall 93*b7893ccfSSadaf Ebrahimi self.apientry = apientry 94*b7893ccfSSadaf Ebrahimi self.apientryp = apientryp 95*b7893ccfSSadaf Ebrahimi self.indentFuncProto = indentFuncProto 96*b7893ccfSSadaf Ebrahimi self.indentFuncPointer = indentFuncPointer 97*b7893ccfSSadaf Ebrahimi self.alignFuncParam = alignFuncParam 98*b7893ccfSSadaf Ebrahimi self.expandEnumerants = expandEnumerants 99*b7893ccfSSadaf Ebrahimi 100*b7893ccfSSadaf Ebrahimi 101*b7893ccfSSadaf Ebrahimi# ThreadOutputGenerator - subclass of OutputGenerator. 102*b7893ccfSSadaf Ebrahimi# Generates Thread checking framework 103*b7893ccfSSadaf Ebrahimi# 104*b7893ccfSSadaf Ebrahimi# ---- methods ---- 105*b7893ccfSSadaf Ebrahimi# ThreadOutputGenerator(errFile, warnFile, diagFile) - args as for 106*b7893ccfSSadaf Ebrahimi# OutputGenerator. Defines additional internal state. 107*b7893ccfSSadaf Ebrahimi# ---- methods overriding base class ---- 108*b7893ccfSSadaf Ebrahimi# beginFile(genOpts) 109*b7893ccfSSadaf Ebrahimi# endFile() 110*b7893ccfSSadaf Ebrahimi# beginFeature(interface, emit) 111*b7893ccfSSadaf Ebrahimi# endFeature() 112*b7893ccfSSadaf Ebrahimi# genType(typeinfo,name) 113*b7893ccfSSadaf Ebrahimi# genStruct(typeinfo,name) 114*b7893ccfSSadaf Ebrahimi# genGroup(groupinfo,name) 115*b7893ccfSSadaf Ebrahimi# genEnum(enuminfo, name) 116*b7893ccfSSadaf Ebrahimi# genCmd(cmdinfo) 117*b7893ccfSSadaf Ebrahimiclass ThreadOutputGenerator(OutputGenerator): 118*b7893ccfSSadaf Ebrahimi """Generate specified API interfaces in a specific style, such as a C header""" 119*b7893ccfSSadaf Ebrahimi 120*b7893ccfSSadaf Ebrahimi inline_copyright_message = """ 121*b7893ccfSSadaf Ebrahimi// This file is ***GENERATED***. Do Not Edit. 122*b7893ccfSSadaf Ebrahimi// See thread_safety_generator.py for modifications. 123*b7893ccfSSadaf Ebrahimi 124*b7893ccfSSadaf Ebrahimi/* Copyright (c) 2015-2019 The Khronos Group Inc. 125*b7893ccfSSadaf Ebrahimi * Copyright (c) 2015-2019 Valve Corporation 126*b7893ccfSSadaf Ebrahimi * Copyright (c) 2015-2019 LunarG, Inc. 127*b7893ccfSSadaf Ebrahimi * Copyright (c) 2015-2019 Google Inc. 128*b7893ccfSSadaf Ebrahimi * 129*b7893ccfSSadaf Ebrahimi * Licensed under the Apache License, Version 2.0 (the "License"); 130*b7893ccfSSadaf Ebrahimi * you may not use this file except in compliance with the License. 131*b7893ccfSSadaf Ebrahimi * You may obtain a copy of the License at 132*b7893ccfSSadaf Ebrahimi * 133*b7893ccfSSadaf Ebrahimi * http://www.apache.org/licenses/LICENSE-2.0 134*b7893ccfSSadaf Ebrahimi * 135*b7893ccfSSadaf Ebrahimi * Unless required by applicable law or agreed to in writing, software 136*b7893ccfSSadaf Ebrahimi * distributed under the License is distributed on an "AS IS" BASIS, 137*b7893ccfSSadaf Ebrahimi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138*b7893ccfSSadaf Ebrahimi * See the License for the specific language governing permissions and 139*b7893ccfSSadaf Ebrahimi * limitations under the License. 140*b7893ccfSSadaf Ebrahimi * 141*b7893ccfSSadaf Ebrahimi * Author: Mark Lobodzinski <[email protected]> 142*b7893ccfSSadaf Ebrahimi */""" 143*b7893ccfSSadaf Ebrahimi 144*b7893ccfSSadaf Ebrahimi # Note that the inline_custom_header_preamble template below contains three embedded template expansion identifiers. 145*b7893ccfSSadaf Ebrahimi # These get replaced with generated code sections, and are labeled: 146*b7893ccfSSadaf Ebrahimi # o COUNTER_CLASS_DEFINITIONS_TEMPLATE 147*b7893ccfSSadaf Ebrahimi # o COUNTER_CLASS_INSTANCES_TEMPLATE 148*b7893ccfSSadaf Ebrahimi # o COUNTER_CLASS_BODIES_TEMPLATE 149*b7893ccfSSadaf Ebrahimi inline_custom_header_preamble = """ 150*b7893ccfSSadaf Ebrahimi#pragma once 151*b7893ccfSSadaf Ebrahimi 152*b7893ccfSSadaf Ebrahimi#include <chrono> 153*b7893ccfSSadaf Ebrahimi#include <thread> 154*b7893ccfSSadaf Ebrahimi#include <mutex> 155*b7893ccfSSadaf Ebrahimi#include <vector> 156*b7893ccfSSadaf Ebrahimi#include <unordered_set> 157*b7893ccfSSadaf Ebrahimi#include <string> 158*b7893ccfSSadaf Ebrahimi 159*b7893ccfSSadaf EbrahimiVK_DEFINE_NON_DISPATCHABLE_HANDLE(DISTINCT_NONDISPATCHABLE_PHONY_HANDLE) 160*b7893ccfSSadaf Ebrahimi// The following line must match the vulkan_core.h condition guarding VK_DEFINE_NON_DISPATCHABLE_HANDLE 161*b7893ccfSSadaf Ebrahimi#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || \ 162*b7893ccfSSadaf Ebrahimi defined(_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) 163*b7893ccfSSadaf Ebrahimi// If pointers are 64-bit, then there can be separate counters for each 164*b7893ccfSSadaf Ebrahimi// NONDISPATCHABLE_HANDLE type. Otherwise they are all typedef uint64_t. 165*b7893ccfSSadaf Ebrahimi#define DISTINCT_NONDISPATCHABLE_HANDLES 166*b7893ccfSSadaf Ebrahimi// Make sure we catch any disagreement between us and the vulkan definition 167*b7893ccfSSadaf Ebrahimistatic_assert(std::is_pointer<DISTINCT_NONDISPATCHABLE_PHONY_HANDLE>::value, 168*b7893ccfSSadaf Ebrahimi "Mismatched non-dispatchable handle handle, expected pointer type."); 169*b7893ccfSSadaf Ebrahimi#else 170*b7893ccfSSadaf Ebrahimi// Make sure we catch any disagreement between us and the vulkan definition 171*b7893ccfSSadaf Ebrahimistatic_assert(std::is_same<uint64_t, DISTINCT_NONDISPATCHABLE_PHONY_HANDLE>::value, 172*b7893ccfSSadaf Ebrahimi "Mismatched non-dispatchable handle handle, expected uint64_t."); 173*b7893ccfSSadaf Ebrahimi#endif 174*b7893ccfSSadaf Ebrahimi 175*b7893ccfSSadaf Ebrahimi// Suppress unused warning on Linux 176*b7893ccfSSadaf Ebrahimi#if defined(__GNUC__) 177*b7893ccfSSadaf Ebrahimi#define DECORATE_UNUSED __attribute__((unused)) 178*b7893ccfSSadaf Ebrahimi#else 179*b7893ccfSSadaf Ebrahimi#define DECORATE_UNUSED 180*b7893ccfSSadaf Ebrahimi#endif 181*b7893ccfSSadaf Ebrahimi 182*b7893ccfSSadaf Ebrahimi// clang-format off 183*b7893ccfSSadaf Ebrahimistatic const char DECORATE_UNUSED *kVUID_Threading_Info = "UNASSIGNED-Threading-Info"; 184*b7893ccfSSadaf Ebrahimistatic const char DECORATE_UNUSED *kVUID_Threading_MultipleThreads = "UNASSIGNED-Threading-MultipleThreads"; 185*b7893ccfSSadaf Ebrahimistatic const char DECORATE_UNUSED *kVUID_Threading_SingleThreadReuse = "UNASSIGNED-Threading-SingleThreadReuse"; 186*b7893ccfSSadaf Ebrahimi// clang-format on 187*b7893ccfSSadaf Ebrahimi 188*b7893ccfSSadaf Ebrahimi#undef DECORATE_UNUSED 189*b7893ccfSSadaf Ebrahimi 190*b7893ccfSSadaf Ebrahimistruct object_use_data { 191*b7893ccfSSadaf Ebrahimi loader_platform_thread_id thread; 192*b7893ccfSSadaf Ebrahimi int reader_count; 193*b7893ccfSSadaf Ebrahimi int writer_count; 194*b7893ccfSSadaf Ebrahimi}; 195*b7893ccfSSadaf Ebrahimi 196*b7893ccfSSadaf Ebrahimi// This is a wrapper around unordered_map that optimizes for the common case 197*b7893ccfSSadaf Ebrahimi// of only containing a single element. The "first" element's use is stored 198*b7893ccfSSadaf Ebrahimi// inline in the class and doesn't require hashing or memory (de)allocation. 199*b7893ccfSSadaf Ebrahimi// TODO: Consider generalizing this from one element to N elements (where N 200*b7893ccfSSadaf Ebrahimi// is a template parameter). 201*b7893ccfSSadaf Ebrahimitemplate <typename Key, typename T> 202*b7893ccfSSadaf Ebrahimiclass small_unordered_map { 203*b7893ccfSSadaf Ebrahimi 204*b7893ccfSSadaf Ebrahimi bool first_data_allocated; 205*b7893ccfSSadaf Ebrahimi Key first_data_key; 206*b7893ccfSSadaf Ebrahimi T first_data; 207*b7893ccfSSadaf Ebrahimi 208*b7893ccfSSadaf Ebrahimi std::unordered_map<Key, T> uses; 209*b7893ccfSSadaf Ebrahimi 210*b7893ccfSSadaf Ebrahimipublic: 211*b7893ccfSSadaf Ebrahimi small_unordered_map() : first_data_allocated(false) {} 212*b7893ccfSSadaf Ebrahimi 213*b7893ccfSSadaf Ebrahimi bool contains(const Key& object) const { 214*b7893ccfSSadaf Ebrahimi if (first_data_allocated && object == first_data_key) { 215*b7893ccfSSadaf Ebrahimi return true; 216*b7893ccfSSadaf Ebrahimi // check size() first to avoid hashing object unnecessarily. 217*b7893ccfSSadaf Ebrahimi } else if (uses.size() == 0) { 218*b7893ccfSSadaf Ebrahimi return false; 219*b7893ccfSSadaf Ebrahimi } else { 220*b7893ccfSSadaf Ebrahimi return uses.find(object) != uses.end(); 221*b7893ccfSSadaf Ebrahimi } 222*b7893ccfSSadaf Ebrahimi } 223*b7893ccfSSadaf Ebrahimi 224*b7893ccfSSadaf Ebrahimi T& operator[](const Key& object) { 225*b7893ccfSSadaf Ebrahimi if (first_data_allocated && first_data_key == object) { 226*b7893ccfSSadaf Ebrahimi return first_data; 227*b7893ccfSSadaf Ebrahimi } else if (!first_data_allocated && uses.size() == 0) { 228*b7893ccfSSadaf Ebrahimi first_data_allocated = true; 229*b7893ccfSSadaf Ebrahimi first_data_key = object; 230*b7893ccfSSadaf Ebrahimi return first_data; 231*b7893ccfSSadaf Ebrahimi } else { 232*b7893ccfSSadaf Ebrahimi return uses[object]; 233*b7893ccfSSadaf Ebrahimi } 234*b7893ccfSSadaf Ebrahimi } 235*b7893ccfSSadaf Ebrahimi 236*b7893ccfSSadaf Ebrahimi typename std::unordered_map<Key, T>::size_type erase(const Key& object) { 237*b7893ccfSSadaf Ebrahimi if (first_data_allocated && first_data_key == object) { 238*b7893ccfSSadaf Ebrahimi first_data_allocated = false; 239*b7893ccfSSadaf Ebrahimi return 1; 240*b7893ccfSSadaf Ebrahimi } else { 241*b7893ccfSSadaf Ebrahimi return uses.erase(object); 242*b7893ccfSSadaf Ebrahimi } 243*b7893ccfSSadaf Ebrahimi } 244*b7893ccfSSadaf Ebrahimi}; 245*b7893ccfSSadaf Ebrahimi 246*b7893ccfSSadaf Ebrahimi#define THREAD_SAFETY_BUCKETS_LOG2 6 247*b7893ccfSSadaf Ebrahimi#define THREAD_SAFETY_BUCKETS (1 << THREAD_SAFETY_BUCKETS_LOG2) 248*b7893ccfSSadaf Ebrahimi 249*b7893ccfSSadaf Ebrahimitemplate <typename T> inline uint32_t ThreadSafetyHashObject(T object) 250*b7893ccfSSadaf Ebrahimi{ 251*b7893ccfSSadaf Ebrahimi uint64_t u64 = (uint64_t)(uintptr_t)object; 252*b7893ccfSSadaf Ebrahimi uint32_t hash = (uint32_t)(u64 >> 32) + (uint32_t)u64; 253*b7893ccfSSadaf Ebrahimi hash ^= (hash >> THREAD_SAFETY_BUCKETS_LOG2) ^ (hash >> (2*THREAD_SAFETY_BUCKETS_LOG2)); 254*b7893ccfSSadaf Ebrahimi hash &= (THREAD_SAFETY_BUCKETS-1); 255*b7893ccfSSadaf Ebrahimi return hash; 256*b7893ccfSSadaf Ebrahimi} 257*b7893ccfSSadaf Ebrahimi 258*b7893ccfSSadaf Ebrahimitemplate <typename T> 259*b7893ccfSSadaf Ebrahimiclass counter { 260*b7893ccfSSadaf Ebrahimipublic: 261*b7893ccfSSadaf Ebrahimi const char *typeName; 262*b7893ccfSSadaf Ebrahimi VkDebugReportObjectTypeEXT objectType; 263*b7893ccfSSadaf Ebrahimi debug_report_data **report_data; 264*b7893ccfSSadaf Ebrahimi 265*b7893ccfSSadaf Ebrahimi // Per-bucket locking, to reduce contention. 266*b7893ccfSSadaf Ebrahimi struct CounterBucket { 267*b7893ccfSSadaf Ebrahimi small_unordered_map<T, object_use_data> uses; 268*b7893ccfSSadaf Ebrahimi std::mutex counter_lock; 269*b7893ccfSSadaf Ebrahimi }; 270*b7893ccfSSadaf Ebrahimi 271*b7893ccfSSadaf Ebrahimi CounterBucket buckets[THREAD_SAFETY_BUCKETS]; 272*b7893ccfSSadaf Ebrahimi CounterBucket &GetBucket(T object) 273*b7893ccfSSadaf Ebrahimi { 274*b7893ccfSSadaf Ebrahimi return buckets[ThreadSafetyHashObject(object)]; 275*b7893ccfSSadaf Ebrahimi } 276*b7893ccfSSadaf Ebrahimi 277*b7893ccfSSadaf Ebrahimi void StartWrite(T object) { 278*b7893ccfSSadaf Ebrahimi if (object == VK_NULL_HANDLE) { 279*b7893ccfSSadaf Ebrahimi return; 280*b7893ccfSSadaf Ebrahimi } 281*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(object); 282*b7893ccfSSadaf Ebrahimi bool skip = false; 283*b7893ccfSSadaf Ebrahimi loader_platform_thread_id tid = loader_platform_get_thread_id(); 284*b7893ccfSSadaf Ebrahimi std::unique_lock<std::mutex> lock(bucket.counter_lock); 285*b7893ccfSSadaf Ebrahimi if (!bucket.uses.contains(object)) { 286*b7893ccfSSadaf Ebrahimi // There is no current use of the object. Record writer thread. 287*b7893ccfSSadaf Ebrahimi struct object_use_data *use_data = &bucket.uses[object]; 288*b7893ccfSSadaf Ebrahimi use_data->reader_count = 0; 289*b7893ccfSSadaf Ebrahimi use_data->writer_count = 1; 290*b7893ccfSSadaf Ebrahimi use_data->thread = tid; 291*b7893ccfSSadaf Ebrahimi } else { 292*b7893ccfSSadaf Ebrahimi struct object_use_data *use_data = &bucket.uses[object]; 293*b7893ccfSSadaf Ebrahimi if (use_data->reader_count == 0) { 294*b7893ccfSSadaf Ebrahimi // There are no readers. Two writers just collided. 295*b7893ccfSSadaf Ebrahimi if (use_data->thread != tid) { 296*b7893ccfSSadaf Ebrahimi skip |= log_msg(*report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object), 297*b7893ccfSSadaf Ebrahimi kVUID_Threading_MultipleThreads, 298*b7893ccfSSadaf Ebrahimi "THREADING ERROR : object of type %s is simultaneously used in " 299*b7893ccfSSadaf Ebrahimi "thread 0x%" PRIx64 " and thread 0x%" PRIx64, 300*b7893ccfSSadaf Ebrahimi typeName, (uint64_t)use_data->thread, (uint64_t)tid); 301*b7893ccfSSadaf Ebrahimi if (skip) { 302*b7893ccfSSadaf Ebrahimi WaitForObjectIdle(bucket, object, lock); 303*b7893ccfSSadaf Ebrahimi // There is now no current use of the object. Record writer thread. 304*b7893ccfSSadaf Ebrahimi struct object_use_data *new_use_data = &bucket.uses[object]; 305*b7893ccfSSadaf Ebrahimi new_use_data->thread = tid; 306*b7893ccfSSadaf Ebrahimi new_use_data->reader_count = 0; 307*b7893ccfSSadaf Ebrahimi new_use_data->writer_count = 1; 308*b7893ccfSSadaf Ebrahimi } else { 309*b7893ccfSSadaf Ebrahimi // Continue with an unsafe use of the object. 310*b7893ccfSSadaf Ebrahimi use_data->thread = tid; 311*b7893ccfSSadaf Ebrahimi use_data->writer_count += 1; 312*b7893ccfSSadaf Ebrahimi } 313*b7893ccfSSadaf Ebrahimi } else { 314*b7893ccfSSadaf Ebrahimi // This is either safe multiple use in one call, or recursive use. 315*b7893ccfSSadaf Ebrahimi // There is no way to make recursion safe. Just forge ahead. 316*b7893ccfSSadaf Ebrahimi use_data->writer_count += 1; 317*b7893ccfSSadaf Ebrahimi } 318*b7893ccfSSadaf Ebrahimi } else { 319*b7893ccfSSadaf Ebrahimi // There are readers. This writer collided with them. 320*b7893ccfSSadaf Ebrahimi if (use_data->thread != tid) { 321*b7893ccfSSadaf Ebrahimi skip |= log_msg(*report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object), 322*b7893ccfSSadaf Ebrahimi kVUID_Threading_MultipleThreads, 323*b7893ccfSSadaf Ebrahimi "THREADING ERROR : object of type %s is simultaneously used in " 324*b7893ccfSSadaf Ebrahimi "thread 0x%" PRIx64 " and thread 0x%" PRIx64, 325*b7893ccfSSadaf Ebrahimi typeName, (uint64_t)use_data->thread, (uint64_t)tid); 326*b7893ccfSSadaf Ebrahimi if (skip) { 327*b7893ccfSSadaf Ebrahimi WaitForObjectIdle(bucket, object, lock); 328*b7893ccfSSadaf Ebrahimi // There is now no current use of the object. Record writer thread. 329*b7893ccfSSadaf Ebrahimi struct object_use_data *new_use_data = &bucket.uses[object]; 330*b7893ccfSSadaf Ebrahimi new_use_data->thread = tid; 331*b7893ccfSSadaf Ebrahimi new_use_data->reader_count = 0; 332*b7893ccfSSadaf Ebrahimi new_use_data->writer_count = 1; 333*b7893ccfSSadaf Ebrahimi } else { 334*b7893ccfSSadaf Ebrahimi // Continue with an unsafe use of the object. 335*b7893ccfSSadaf Ebrahimi use_data->thread = tid; 336*b7893ccfSSadaf Ebrahimi use_data->writer_count += 1; 337*b7893ccfSSadaf Ebrahimi } 338*b7893ccfSSadaf Ebrahimi } else { 339*b7893ccfSSadaf Ebrahimi // This is either safe multiple use in one call, or recursive use. 340*b7893ccfSSadaf Ebrahimi // There is no way to make recursion safe. Just forge ahead. 341*b7893ccfSSadaf Ebrahimi use_data->writer_count += 1; 342*b7893ccfSSadaf Ebrahimi } 343*b7893ccfSSadaf Ebrahimi } 344*b7893ccfSSadaf Ebrahimi } 345*b7893ccfSSadaf Ebrahimi } 346*b7893ccfSSadaf Ebrahimi 347*b7893ccfSSadaf Ebrahimi void FinishWrite(T object) { 348*b7893ccfSSadaf Ebrahimi if (object == VK_NULL_HANDLE) { 349*b7893ccfSSadaf Ebrahimi return; 350*b7893ccfSSadaf Ebrahimi } 351*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(object); 352*b7893ccfSSadaf Ebrahimi // Object is no longer in use 353*b7893ccfSSadaf Ebrahimi std::unique_lock<std::mutex> lock(bucket.counter_lock); 354*b7893ccfSSadaf Ebrahimi struct object_use_data *use_data = &bucket.uses[object]; 355*b7893ccfSSadaf Ebrahimi use_data->writer_count -= 1; 356*b7893ccfSSadaf Ebrahimi if ((use_data->reader_count == 0) && (use_data->writer_count == 0)) { 357*b7893ccfSSadaf Ebrahimi bucket.uses.erase(object); 358*b7893ccfSSadaf Ebrahimi } 359*b7893ccfSSadaf Ebrahimi } 360*b7893ccfSSadaf Ebrahimi 361*b7893ccfSSadaf Ebrahimi void StartRead(T object) { 362*b7893ccfSSadaf Ebrahimi if (object == VK_NULL_HANDLE) { 363*b7893ccfSSadaf Ebrahimi return; 364*b7893ccfSSadaf Ebrahimi } 365*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(object); 366*b7893ccfSSadaf Ebrahimi bool skip = false; 367*b7893ccfSSadaf Ebrahimi loader_platform_thread_id tid = loader_platform_get_thread_id(); 368*b7893ccfSSadaf Ebrahimi std::unique_lock<std::mutex> lock(bucket.counter_lock); 369*b7893ccfSSadaf Ebrahimi if (!bucket.uses.contains(object)) { 370*b7893ccfSSadaf Ebrahimi // There is no current use of the object. Record reader count 371*b7893ccfSSadaf Ebrahimi struct object_use_data *use_data = &bucket.uses[object]; 372*b7893ccfSSadaf Ebrahimi use_data->reader_count = 1; 373*b7893ccfSSadaf Ebrahimi use_data->writer_count = 0; 374*b7893ccfSSadaf Ebrahimi use_data->thread = tid; 375*b7893ccfSSadaf Ebrahimi } else if (bucket.uses[object].writer_count > 0 && bucket.uses[object].thread != tid) { 376*b7893ccfSSadaf Ebrahimi // There is a writer of the object. 377*b7893ccfSSadaf Ebrahimi skip |= log_msg(*report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, (uint64_t)(object), 378*b7893ccfSSadaf Ebrahimi kVUID_Threading_MultipleThreads, 379*b7893ccfSSadaf Ebrahimi "THREADING ERROR : object of type %s is simultaneously used in " 380*b7893ccfSSadaf Ebrahimi "thread 0x%" PRIx64 " and thread 0x%" PRIx64, 381*b7893ccfSSadaf Ebrahimi typeName, (uint64_t)bucket.uses[object].thread, (uint64_t)tid); 382*b7893ccfSSadaf Ebrahimi if (skip) { 383*b7893ccfSSadaf Ebrahimi WaitForObjectIdle(bucket, object, lock); 384*b7893ccfSSadaf Ebrahimi // There is no current use of the object. Record reader count 385*b7893ccfSSadaf Ebrahimi struct object_use_data *use_data = &bucket.uses[object]; 386*b7893ccfSSadaf Ebrahimi use_data->reader_count = 1; 387*b7893ccfSSadaf Ebrahimi use_data->writer_count = 0; 388*b7893ccfSSadaf Ebrahimi use_data->thread = tid; 389*b7893ccfSSadaf Ebrahimi } else { 390*b7893ccfSSadaf Ebrahimi bucket.uses[object].reader_count += 1; 391*b7893ccfSSadaf Ebrahimi } 392*b7893ccfSSadaf Ebrahimi } else { 393*b7893ccfSSadaf Ebrahimi // There are other readers of the object. Increase reader count 394*b7893ccfSSadaf Ebrahimi bucket.uses[object].reader_count += 1; 395*b7893ccfSSadaf Ebrahimi } 396*b7893ccfSSadaf Ebrahimi } 397*b7893ccfSSadaf Ebrahimi void FinishRead(T object) { 398*b7893ccfSSadaf Ebrahimi if (object == VK_NULL_HANDLE) { 399*b7893ccfSSadaf Ebrahimi return; 400*b7893ccfSSadaf Ebrahimi } 401*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(object); 402*b7893ccfSSadaf Ebrahimi std::unique_lock<std::mutex> lock(bucket.counter_lock); 403*b7893ccfSSadaf Ebrahimi struct object_use_data *use_data = &bucket.uses[object]; 404*b7893ccfSSadaf Ebrahimi use_data->reader_count -= 1; 405*b7893ccfSSadaf Ebrahimi if ((use_data->reader_count == 0) && (use_data->writer_count == 0)) { 406*b7893ccfSSadaf Ebrahimi bucket.uses.erase(object); 407*b7893ccfSSadaf Ebrahimi } 408*b7893ccfSSadaf Ebrahimi } 409*b7893ccfSSadaf Ebrahimi counter(const char *name = "", VkDebugReportObjectTypeEXT type = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, debug_report_data **rep_data = nullptr) { 410*b7893ccfSSadaf Ebrahimi typeName = name; 411*b7893ccfSSadaf Ebrahimi objectType = type; 412*b7893ccfSSadaf Ebrahimi report_data = rep_data; 413*b7893ccfSSadaf Ebrahimi } 414*b7893ccfSSadaf Ebrahimi 415*b7893ccfSSadaf Ebrahimiprivate: 416*b7893ccfSSadaf Ebrahimi void WaitForObjectIdle(CounterBucket &bucket, T object, std::unique_lock<std::mutex> &lock) { 417*b7893ccfSSadaf Ebrahimi // Wait for thread-safe access to object instead of skipping call. 418*b7893ccfSSadaf Ebrahimi // Don't use condition_variable to wait because it should be extremely 419*b7893ccfSSadaf Ebrahimi // rare to have collisions, but signaling would be very frequent. 420*b7893ccfSSadaf Ebrahimi while (bucket.uses.contains(object)) { 421*b7893ccfSSadaf Ebrahimi lock.unlock(); 422*b7893ccfSSadaf Ebrahimi std::this_thread::sleep_for(std::chrono::microseconds(1)); 423*b7893ccfSSadaf Ebrahimi lock.lock(); 424*b7893ccfSSadaf Ebrahimi } 425*b7893ccfSSadaf Ebrahimi } 426*b7893ccfSSadaf Ebrahimi}; 427*b7893ccfSSadaf Ebrahimi 428*b7893ccfSSadaf Ebrahimi 429*b7893ccfSSadaf Ebrahimi 430*b7893ccfSSadaf Ebrahimiclass ThreadSafety : public ValidationObject { 431*b7893ccfSSadaf Ebrahimipublic: 432*b7893ccfSSadaf Ebrahimi 433*b7893ccfSSadaf Ebrahimi // Override chassis read/write locks for this validation object 434*b7893ccfSSadaf Ebrahimi // This override takes a deferred lock. i.e. it is not acquired. 435*b7893ccfSSadaf Ebrahimi std::unique_lock<std::mutex> write_lock() { 436*b7893ccfSSadaf Ebrahimi return std::unique_lock<std::mutex>(validation_object_mutex, std::defer_lock); 437*b7893ccfSSadaf Ebrahimi } 438*b7893ccfSSadaf Ebrahimi 439*b7893ccfSSadaf Ebrahimi // Per-bucket locking, to reduce contention. 440*b7893ccfSSadaf Ebrahimi struct CommandBufferBucket { 441*b7893ccfSSadaf Ebrahimi std::mutex command_pool_lock; 442*b7893ccfSSadaf Ebrahimi small_unordered_map<VkCommandBuffer, VkCommandPool> command_pool_map; 443*b7893ccfSSadaf Ebrahimi }; 444*b7893ccfSSadaf Ebrahimi 445*b7893ccfSSadaf Ebrahimi CommandBufferBucket buckets[THREAD_SAFETY_BUCKETS]; 446*b7893ccfSSadaf Ebrahimi CommandBufferBucket &GetBucket(VkCommandBuffer object) 447*b7893ccfSSadaf Ebrahimi { 448*b7893ccfSSadaf Ebrahimi return buckets[ThreadSafetyHashObject(object)]; 449*b7893ccfSSadaf Ebrahimi } 450*b7893ccfSSadaf Ebrahimi 451*b7893ccfSSadaf Ebrahimi counter<VkCommandBuffer> c_VkCommandBuffer; 452*b7893ccfSSadaf Ebrahimi counter<VkDevice> c_VkDevice; 453*b7893ccfSSadaf Ebrahimi counter<VkInstance> c_VkInstance; 454*b7893ccfSSadaf Ebrahimi counter<VkQueue> c_VkQueue; 455*b7893ccfSSadaf Ebrahimi#ifdef DISTINCT_NONDISPATCHABLE_HANDLES 456*b7893ccfSSadaf Ebrahimi 457*b7893ccfSSadaf Ebrahimi // Special entry to allow tracking of command pool Reset and Destroy 458*b7893ccfSSadaf Ebrahimi counter<VkCommandPool> c_VkCommandPoolContents; 459*b7893ccfSSadaf EbrahimiCOUNTER_CLASS_DEFINITIONS_TEMPLATE 460*b7893ccfSSadaf Ebrahimi 461*b7893ccfSSadaf Ebrahimi#else // DISTINCT_NONDISPATCHABLE_HANDLES 462*b7893ccfSSadaf Ebrahimi // Special entry to allow tracking of command pool Reset and Destroy 463*b7893ccfSSadaf Ebrahimi counter<uint64_t> c_VkCommandPoolContents; 464*b7893ccfSSadaf Ebrahimi 465*b7893ccfSSadaf Ebrahimi counter<uint64_t> c_uint64_t; 466*b7893ccfSSadaf Ebrahimi#endif // DISTINCT_NONDISPATCHABLE_HANDLES 467*b7893ccfSSadaf Ebrahimi 468*b7893ccfSSadaf Ebrahimi ThreadSafety() 469*b7893ccfSSadaf Ebrahimi : c_VkCommandBuffer("VkCommandBuffer", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, &report_data), 470*b7893ccfSSadaf Ebrahimi c_VkDevice("VkDevice", VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, &report_data), 471*b7893ccfSSadaf Ebrahimi c_VkInstance("VkInstance", VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, &report_data), 472*b7893ccfSSadaf Ebrahimi c_VkQueue("VkQueue", VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT, &report_data), 473*b7893ccfSSadaf Ebrahimi c_VkCommandPoolContents("VkCommandPool", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT, &report_data), 474*b7893ccfSSadaf Ebrahimi 475*b7893ccfSSadaf Ebrahimi#ifdef DISTINCT_NONDISPATCHABLE_HANDLES 476*b7893ccfSSadaf EbrahimiCOUNTER_CLASS_INSTANCES_TEMPLATE 477*b7893ccfSSadaf Ebrahimi 478*b7893ccfSSadaf Ebrahimi 479*b7893ccfSSadaf Ebrahimi#else // DISTINCT_NONDISPATCHABLE_HANDLES 480*b7893ccfSSadaf Ebrahimi c_uint64_t("NON_DISPATCHABLE_HANDLE", VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, &report_data) 481*b7893ccfSSadaf Ebrahimi#endif // DISTINCT_NONDISPATCHABLE_HANDLES 482*b7893ccfSSadaf Ebrahimi {}; 483*b7893ccfSSadaf Ebrahimi 484*b7893ccfSSadaf Ebrahimi#define WRAPPER(type) \ 485*b7893ccfSSadaf Ebrahimi void StartWriteObject(type object) { \ 486*b7893ccfSSadaf Ebrahimi c_##type.StartWrite(object); \ 487*b7893ccfSSadaf Ebrahimi } \ 488*b7893ccfSSadaf Ebrahimi void FinishWriteObject(type object) { \ 489*b7893ccfSSadaf Ebrahimi c_##type.FinishWrite(object); \ 490*b7893ccfSSadaf Ebrahimi } \ 491*b7893ccfSSadaf Ebrahimi void StartReadObject(type object) { \ 492*b7893ccfSSadaf Ebrahimi c_##type.StartRead(object); \ 493*b7893ccfSSadaf Ebrahimi } \ 494*b7893ccfSSadaf Ebrahimi void FinishReadObject(type object) { \ 495*b7893ccfSSadaf Ebrahimi c_##type.FinishRead(object); \ 496*b7893ccfSSadaf Ebrahimi } 497*b7893ccfSSadaf Ebrahimi 498*b7893ccfSSadaf EbrahimiWRAPPER(VkDevice) 499*b7893ccfSSadaf EbrahimiWRAPPER(VkInstance) 500*b7893ccfSSadaf EbrahimiWRAPPER(VkQueue) 501*b7893ccfSSadaf Ebrahimi#ifdef DISTINCT_NONDISPATCHABLE_HANDLES 502*b7893ccfSSadaf EbrahimiCOUNTER_CLASS_BODIES_TEMPLATE 503*b7893ccfSSadaf Ebrahimi 504*b7893ccfSSadaf Ebrahimi#else // DISTINCT_NONDISPATCHABLE_HANDLES 505*b7893ccfSSadaf EbrahimiWRAPPER(uint64_t) 506*b7893ccfSSadaf Ebrahimi#endif // DISTINCT_NONDISPATCHABLE_HANDLES 507*b7893ccfSSadaf Ebrahimi 508*b7893ccfSSadaf Ebrahimi // VkCommandBuffer needs check for implicit use of command pool 509*b7893ccfSSadaf Ebrahimi void StartWriteObject(VkCommandBuffer object, bool lockPool = true) { 510*b7893ccfSSadaf Ebrahimi if (lockPool) { 511*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(object); 512*b7893ccfSSadaf Ebrahimi std::unique_lock<std::mutex> lock(bucket.command_pool_lock); 513*b7893ccfSSadaf Ebrahimi VkCommandPool pool = bucket.command_pool_map[object]; 514*b7893ccfSSadaf Ebrahimi lock.unlock(); 515*b7893ccfSSadaf Ebrahimi StartWriteObject(pool); 516*b7893ccfSSadaf Ebrahimi } 517*b7893ccfSSadaf Ebrahimi c_VkCommandBuffer.StartWrite(object); 518*b7893ccfSSadaf Ebrahimi } 519*b7893ccfSSadaf Ebrahimi void FinishWriteObject(VkCommandBuffer object, bool lockPool = true) { 520*b7893ccfSSadaf Ebrahimi c_VkCommandBuffer.FinishWrite(object); 521*b7893ccfSSadaf Ebrahimi if (lockPool) { 522*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(object); 523*b7893ccfSSadaf Ebrahimi std::unique_lock<std::mutex> lock(bucket.command_pool_lock); 524*b7893ccfSSadaf Ebrahimi VkCommandPool pool = bucket.command_pool_map[object]; 525*b7893ccfSSadaf Ebrahimi lock.unlock(); 526*b7893ccfSSadaf Ebrahimi FinishWriteObject(pool); 527*b7893ccfSSadaf Ebrahimi } 528*b7893ccfSSadaf Ebrahimi } 529*b7893ccfSSadaf Ebrahimi void StartReadObject(VkCommandBuffer object) { 530*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(object); 531*b7893ccfSSadaf Ebrahimi std::unique_lock<std::mutex> lock(bucket.command_pool_lock); 532*b7893ccfSSadaf Ebrahimi VkCommandPool pool = bucket.command_pool_map[object]; 533*b7893ccfSSadaf Ebrahimi lock.unlock(); 534*b7893ccfSSadaf Ebrahimi // We set up a read guard against the "Contents" counter to catch conflict vs. vkResetCommandPool and vkDestroyCommandPool 535*b7893ccfSSadaf Ebrahimi // while *not* establishing a read guard against the command pool counter itself to avoid false postives for 536*b7893ccfSSadaf Ebrahimi // non-externally sync'd command buffers 537*b7893ccfSSadaf Ebrahimi c_VkCommandPoolContents.StartRead(pool); 538*b7893ccfSSadaf Ebrahimi c_VkCommandBuffer.StartRead(object); 539*b7893ccfSSadaf Ebrahimi } 540*b7893ccfSSadaf Ebrahimi void FinishReadObject(VkCommandBuffer object) { 541*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(object); 542*b7893ccfSSadaf Ebrahimi c_VkCommandBuffer.FinishRead(object); 543*b7893ccfSSadaf Ebrahimi std::unique_lock<std::mutex> lock(bucket.command_pool_lock); 544*b7893ccfSSadaf Ebrahimi VkCommandPool pool = bucket.command_pool_map[object]; 545*b7893ccfSSadaf Ebrahimi lock.unlock(); 546*b7893ccfSSadaf Ebrahimi c_VkCommandPoolContents.FinishRead(pool); 547*b7893ccfSSadaf Ebrahimi } """ 548*b7893ccfSSadaf Ebrahimi 549*b7893ccfSSadaf Ebrahimi 550*b7893ccfSSadaf Ebrahimi inline_custom_source_preamble = """ 551*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PreCallRecordAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, 552*b7893ccfSSadaf Ebrahimi VkCommandBuffer *pCommandBuffers) { 553*b7893ccfSSadaf Ebrahimi StartReadObject(device); 554*b7893ccfSSadaf Ebrahimi StartWriteObject(pAllocateInfo->commandPool); 555*b7893ccfSSadaf Ebrahimi} 556*b7893ccfSSadaf Ebrahimi 557*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PostCallRecordAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, 558*b7893ccfSSadaf Ebrahimi VkCommandBuffer *pCommandBuffers, VkResult result) { 559*b7893ccfSSadaf Ebrahimi FinishReadObject(device); 560*b7893ccfSSadaf Ebrahimi FinishWriteObject(pAllocateInfo->commandPool); 561*b7893ccfSSadaf Ebrahimi 562*b7893ccfSSadaf Ebrahimi // Record mapping from command buffer to command pool 563*b7893ccfSSadaf Ebrahimi if(pCommandBuffers) { 564*b7893ccfSSadaf Ebrahimi for (uint32_t index = 0; index < pAllocateInfo->commandBufferCount; index++) { 565*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(pCommandBuffers[index]); 566*b7893ccfSSadaf Ebrahimi std::lock_guard<std::mutex> lock(bucket.command_pool_lock); 567*b7893ccfSSadaf Ebrahimi bucket.command_pool_map[pCommandBuffers[index]] = pAllocateInfo->commandPool; 568*b7893ccfSSadaf Ebrahimi } 569*b7893ccfSSadaf Ebrahimi } 570*b7893ccfSSadaf Ebrahimi} 571*b7893ccfSSadaf Ebrahimi 572*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PreCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, 573*b7893ccfSSadaf Ebrahimi VkDescriptorSet *pDescriptorSets) { 574*b7893ccfSSadaf Ebrahimi StartReadObject(device); 575*b7893ccfSSadaf Ebrahimi StartWriteObject(pAllocateInfo->descriptorPool); 576*b7893ccfSSadaf Ebrahimi // Host access to pAllocateInfo::descriptorPool must be externally synchronized 577*b7893ccfSSadaf Ebrahimi} 578*b7893ccfSSadaf Ebrahimi 579*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PostCallRecordAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, 580*b7893ccfSSadaf Ebrahimi VkDescriptorSet *pDescriptorSets, VkResult result) { 581*b7893ccfSSadaf Ebrahimi FinishReadObject(device); 582*b7893ccfSSadaf Ebrahimi FinishWriteObject(pAllocateInfo->descriptorPool); 583*b7893ccfSSadaf Ebrahimi // Host access to pAllocateInfo::descriptorPool must be externally synchronized 584*b7893ccfSSadaf Ebrahimi} 585*b7893ccfSSadaf Ebrahimi 586*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PreCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, 587*b7893ccfSSadaf Ebrahimi const VkCommandBuffer *pCommandBuffers) { 588*b7893ccfSSadaf Ebrahimi const bool lockCommandPool = false; // pool is already directly locked 589*b7893ccfSSadaf Ebrahimi StartReadObject(device); 590*b7893ccfSSadaf Ebrahimi StartWriteObject(commandPool); 591*b7893ccfSSadaf Ebrahimi if(pCommandBuffers) { 592*b7893ccfSSadaf Ebrahimi // Even though we're immediately "finishing" below, we still are testing for concurrency with any call in process 593*b7893ccfSSadaf Ebrahimi // so this isn't a no-op 594*b7893ccfSSadaf Ebrahimi for (uint32_t index = 0; index < commandBufferCount; index++) { 595*b7893ccfSSadaf Ebrahimi StartWriteObject(pCommandBuffers[index], lockCommandPool); 596*b7893ccfSSadaf Ebrahimi } 597*b7893ccfSSadaf Ebrahimi // The driver may immediately reuse command buffers in another thread. 598*b7893ccfSSadaf Ebrahimi // These updates need to be done before calling down to the driver. 599*b7893ccfSSadaf Ebrahimi for (uint32_t index = 0; index < commandBufferCount; index++) { 600*b7893ccfSSadaf Ebrahimi FinishWriteObject(pCommandBuffers[index], lockCommandPool); 601*b7893ccfSSadaf Ebrahimi } 602*b7893ccfSSadaf Ebrahimi // Holding the lock for the shortest time while we update the map 603*b7893ccfSSadaf Ebrahimi for (uint32_t index = 0; index < commandBufferCount; index++) { 604*b7893ccfSSadaf Ebrahimi auto &bucket = GetBucket(pCommandBuffers[index]); 605*b7893ccfSSadaf Ebrahimi std::lock_guard<std::mutex> lock(bucket.command_pool_lock); 606*b7893ccfSSadaf Ebrahimi bucket.command_pool_map.erase(pCommandBuffers[index]); 607*b7893ccfSSadaf Ebrahimi } 608*b7893ccfSSadaf Ebrahimi } 609*b7893ccfSSadaf Ebrahimi} 610*b7893ccfSSadaf Ebrahimi 611*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PostCallRecordFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, 612*b7893ccfSSadaf Ebrahimi const VkCommandBuffer *pCommandBuffers) { 613*b7893ccfSSadaf Ebrahimi FinishReadObject(device); 614*b7893ccfSSadaf Ebrahimi FinishWriteObject(commandPool); 615*b7893ccfSSadaf Ebrahimi} 616*b7893ccfSSadaf Ebrahimi 617*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PreCallRecordResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) { 618*b7893ccfSSadaf Ebrahimi StartReadObject(device); 619*b7893ccfSSadaf Ebrahimi StartWriteObject(commandPool); 620*b7893ccfSSadaf Ebrahimi // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands) 621*b7893ccfSSadaf Ebrahimi c_VkCommandPoolContents.StartWrite(commandPool); 622*b7893ccfSSadaf Ebrahimi // Host access to commandPool must be externally synchronized 623*b7893ccfSSadaf Ebrahimi} 624*b7893ccfSSadaf Ebrahimi 625*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PostCallRecordResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags, VkResult result) { 626*b7893ccfSSadaf Ebrahimi FinishReadObject(device); 627*b7893ccfSSadaf Ebrahimi FinishWriteObject(commandPool); 628*b7893ccfSSadaf Ebrahimi c_VkCommandPoolContents.FinishWrite(commandPool); 629*b7893ccfSSadaf Ebrahimi // Host access to commandPool must be externally synchronized 630*b7893ccfSSadaf Ebrahimi} 631*b7893ccfSSadaf Ebrahimi 632*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PreCallRecordDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) { 633*b7893ccfSSadaf Ebrahimi StartReadObject(device); 634*b7893ccfSSadaf Ebrahimi StartWriteObject(commandPool); 635*b7893ccfSSadaf Ebrahimi // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands) 636*b7893ccfSSadaf Ebrahimi c_VkCommandPoolContents.StartWrite(commandPool); 637*b7893ccfSSadaf Ebrahimi // Host access to commandPool must be externally synchronized 638*b7893ccfSSadaf Ebrahimi} 639*b7893ccfSSadaf Ebrahimi 640*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PostCallRecordDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) { 641*b7893ccfSSadaf Ebrahimi FinishReadObject(device); 642*b7893ccfSSadaf Ebrahimi FinishWriteObject(commandPool); 643*b7893ccfSSadaf Ebrahimi c_VkCommandPoolContents.FinishWrite(commandPool); 644*b7893ccfSSadaf Ebrahimi} 645*b7893ccfSSadaf Ebrahimi 646*b7893ccfSSadaf Ebrahimi// GetSwapchainImages can return a non-zero count with a NULL pSwapchainImages pointer. Let's avoid crashes by ignoring 647*b7893ccfSSadaf Ebrahimi// pSwapchainImages. 648*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PreCallRecordGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, 649*b7893ccfSSadaf Ebrahimi VkImage *pSwapchainImages) { 650*b7893ccfSSadaf Ebrahimi StartReadObject(device); 651*b7893ccfSSadaf Ebrahimi StartReadObject(swapchain); 652*b7893ccfSSadaf Ebrahimi} 653*b7893ccfSSadaf Ebrahimi 654*b7893ccfSSadaf Ebrahimivoid ThreadSafety::PostCallRecordGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, 655*b7893ccfSSadaf Ebrahimi VkImage *pSwapchainImages, VkResult result) { 656*b7893ccfSSadaf Ebrahimi FinishReadObject(device); 657*b7893ccfSSadaf Ebrahimi FinishReadObject(swapchain); 658*b7893ccfSSadaf Ebrahimi} 659*b7893ccfSSadaf Ebrahimi 660*b7893ccfSSadaf Ebrahimi""" 661*b7893ccfSSadaf Ebrahimi 662*b7893ccfSSadaf Ebrahimi 663*b7893ccfSSadaf Ebrahimi # This is an ordered list of sections in the header file. 664*b7893ccfSSadaf Ebrahimi ALL_SECTIONS = ['command'] 665*b7893ccfSSadaf Ebrahimi def __init__(self, 666*b7893ccfSSadaf Ebrahimi errFile = sys.stderr, 667*b7893ccfSSadaf Ebrahimi warnFile = sys.stderr, 668*b7893ccfSSadaf Ebrahimi diagFile = sys.stdout): 669*b7893ccfSSadaf Ebrahimi OutputGenerator.__init__(self, errFile, warnFile, diagFile) 670*b7893ccfSSadaf Ebrahimi # Internal state - accumulators for different inner block text 671*b7893ccfSSadaf Ebrahimi self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) 672*b7893ccfSSadaf Ebrahimi self.non_dispatchable_types = set() 673*b7893ccfSSadaf Ebrahimi self.object_to_debug_report_type = { 674*b7893ccfSSadaf Ebrahimi 'VkInstance' : 'VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT', 675*b7893ccfSSadaf Ebrahimi 'VkPhysicalDevice' : 'VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT', 676*b7893ccfSSadaf Ebrahimi 'VkDevice' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT', 677*b7893ccfSSadaf Ebrahimi 'VkQueue' : 'VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT', 678*b7893ccfSSadaf Ebrahimi 'VkSemaphore' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT', 679*b7893ccfSSadaf Ebrahimi 'VkCommandBuffer' : 'VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT', 680*b7893ccfSSadaf Ebrahimi 'VkFence' : 'VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT', 681*b7893ccfSSadaf Ebrahimi 'VkDeviceMemory' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT', 682*b7893ccfSSadaf Ebrahimi 'VkBuffer' : 'VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT', 683*b7893ccfSSadaf Ebrahimi 'VkImage' : 'VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT', 684*b7893ccfSSadaf Ebrahimi 'VkEvent' : 'VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT', 685*b7893ccfSSadaf Ebrahimi 'VkQueryPool' : 'VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT', 686*b7893ccfSSadaf Ebrahimi 'VkBufferView' : 'VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT', 687*b7893ccfSSadaf Ebrahimi 'VkImageView' : 'VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT', 688*b7893ccfSSadaf Ebrahimi 'VkShaderModule' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT', 689*b7893ccfSSadaf Ebrahimi 'VkPipelineCache' : 'VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT', 690*b7893ccfSSadaf Ebrahimi 'VkPipelineLayout' : 'VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT', 691*b7893ccfSSadaf Ebrahimi 'VkRenderPass' : 'VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT', 692*b7893ccfSSadaf Ebrahimi 'VkPipeline' : 'VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT', 693*b7893ccfSSadaf Ebrahimi 'VkDescriptorSetLayout' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT', 694*b7893ccfSSadaf Ebrahimi 'VkSampler' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT', 695*b7893ccfSSadaf Ebrahimi 'VkDescriptorPool' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT', 696*b7893ccfSSadaf Ebrahimi 'VkDescriptorSet' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT', 697*b7893ccfSSadaf Ebrahimi 'VkFramebuffer' : 'VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT', 698*b7893ccfSSadaf Ebrahimi 'VkCommandPool' : 'VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT', 699*b7893ccfSSadaf Ebrahimi 'VkSurfaceKHR' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT', 700*b7893ccfSSadaf Ebrahimi 'VkSwapchainKHR' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT', 701*b7893ccfSSadaf Ebrahimi 'VkDisplayKHR' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT', 702*b7893ccfSSadaf Ebrahimi 'VkDisplayModeKHR' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT', 703*b7893ccfSSadaf Ebrahimi 'VkObjectTableNVX' : 'VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT', 704*b7893ccfSSadaf Ebrahimi 'VkIndirectCommandsLayoutNVX' : 'VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT', 705*b7893ccfSSadaf Ebrahimi 'VkSamplerYcbcrConversion' : 'VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT', 706*b7893ccfSSadaf Ebrahimi 'VkDescriptorUpdateTemplate' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT', 707*b7893ccfSSadaf Ebrahimi 'VkAccelerationStructureNV' : 'VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT', 708*b7893ccfSSadaf Ebrahimi 'VkDebugReportCallbackEXT' : 'VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT', 709*b7893ccfSSadaf Ebrahimi 'VkValidationCacheEXT' : 'VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT' } 710*b7893ccfSSadaf Ebrahimi 711*b7893ccfSSadaf Ebrahimi # Check if the parameter passed in is a pointer to an array 712*b7893ccfSSadaf Ebrahimi def paramIsArray(self, param): 713*b7893ccfSSadaf Ebrahimi return param.attrib.get('len') is not None 714*b7893ccfSSadaf Ebrahimi 715*b7893ccfSSadaf Ebrahimi # Check if the parameter passed in is a pointer 716*b7893ccfSSadaf Ebrahimi def paramIsPointer(self, param): 717*b7893ccfSSadaf Ebrahimi ispointer = False 718*b7893ccfSSadaf Ebrahimi for elem in param: 719*b7893ccfSSadaf Ebrahimi if elem.tag == 'type' and elem.tail is not None and '*' in elem.tail: 720*b7893ccfSSadaf Ebrahimi ispointer = True 721*b7893ccfSSadaf Ebrahimi return ispointer 722*b7893ccfSSadaf Ebrahimi 723*b7893ccfSSadaf Ebrahimi def makeThreadUseBlock(self, cmd, functionprefix): 724*b7893ccfSSadaf Ebrahimi """Generate C function pointer typedef for <command> Element""" 725*b7893ccfSSadaf Ebrahimi paramdecl = '' 726*b7893ccfSSadaf Ebrahimi # Find and add any parameters that are thread unsafe 727*b7893ccfSSadaf Ebrahimi params = cmd.findall('param') 728*b7893ccfSSadaf Ebrahimi for param in params: 729*b7893ccfSSadaf Ebrahimi paramname = param.find('name') 730*b7893ccfSSadaf Ebrahimi if False: # self.paramIsPointer(param): 731*b7893ccfSSadaf Ebrahimi paramdecl += ' // not watching use of pointer ' + paramname.text + '\n' 732*b7893ccfSSadaf Ebrahimi else: 733*b7893ccfSSadaf Ebrahimi externsync = param.attrib.get('externsync') 734*b7893ccfSSadaf Ebrahimi if externsync == 'true': 735*b7893ccfSSadaf Ebrahimi if self.paramIsArray(param): 736*b7893ccfSSadaf Ebrahimi paramdecl += 'if (' + paramname.text + ') {\n' 737*b7893ccfSSadaf Ebrahimi paramdecl += ' for (uint32_t index=0; index < ' + param.attrib.get('len') + '; index++) {\n' 738*b7893ccfSSadaf Ebrahimi paramdecl += ' ' + functionprefix + 'WriteObject(' + paramname.text + '[index]);\n' 739*b7893ccfSSadaf Ebrahimi paramdecl += ' }\n' 740*b7893ccfSSadaf Ebrahimi paramdecl += '}\n' 741*b7893ccfSSadaf Ebrahimi else: 742*b7893ccfSSadaf Ebrahimi paramdecl += functionprefix + 'WriteObject(' + paramname.text + ');\n' 743*b7893ccfSSadaf Ebrahimi elif (param.attrib.get('externsync')): 744*b7893ccfSSadaf Ebrahimi if self.paramIsArray(param): 745*b7893ccfSSadaf Ebrahimi # Externsync can list pointers to arrays of members to synchronize 746*b7893ccfSSadaf Ebrahimi paramdecl += 'if (' + paramname.text + ') {\n' 747*b7893ccfSSadaf Ebrahimi paramdecl += ' for (uint32_t index=0; index < ' + param.attrib.get('len') + '; index++) {\n' 748*b7893ccfSSadaf Ebrahimi second_indent = ' ' 749*b7893ccfSSadaf Ebrahimi for member in externsync.split(","): 750*b7893ccfSSadaf Ebrahimi # Replace first empty [] in member name with index 751*b7893ccfSSadaf Ebrahimi element = member.replace('[]','[index]',1) 752*b7893ccfSSadaf Ebrahimi if '[]' in element: 753*b7893ccfSSadaf Ebrahimi # TODO: These null checks can be removed if threading ends up behind parameter 754*b7893ccfSSadaf Ebrahimi # validation in layer order 755*b7893ccfSSadaf Ebrahimi element_ptr = element.split('[]')[0] 756*b7893ccfSSadaf Ebrahimi paramdecl += ' if (' + element_ptr + ') {\n' 757*b7893ccfSSadaf Ebrahimi # Replace any second empty [] in element name with inner array index based on mapping array 758*b7893ccfSSadaf Ebrahimi # names like "pSomeThings[]" to "someThingCount" array size. This could be more robust by 759*b7893ccfSSadaf Ebrahimi # mapping a param member name to a struct type and "len" attribute. 760*b7893ccfSSadaf Ebrahimi limit = element[0:element.find('s[]')] + 'Count' 761*b7893ccfSSadaf Ebrahimi dotp = limit.rfind('.p') 762*b7893ccfSSadaf Ebrahimi limit = limit[0:dotp+1] + limit[dotp+2:dotp+3].lower() + limit[dotp+3:] 763*b7893ccfSSadaf Ebrahimi paramdecl += ' for (uint32_t index2=0; index2 < '+limit+'; index2++) {\n' 764*b7893ccfSSadaf Ebrahimi element = element.replace('[]','[index2]') 765*b7893ccfSSadaf Ebrahimi second_indent = ' ' 766*b7893ccfSSadaf Ebrahimi paramdecl += ' ' + second_indent + functionprefix + 'WriteObject(' + element + ');\n' 767*b7893ccfSSadaf Ebrahimi paramdecl += ' }\n' 768*b7893ccfSSadaf Ebrahimi paramdecl += ' }\n' 769*b7893ccfSSadaf Ebrahimi else: 770*b7893ccfSSadaf Ebrahimi paramdecl += ' ' + second_indent + functionprefix + 'WriteObject(' + element + ');\n' 771*b7893ccfSSadaf Ebrahimi paramdecl += ' }\n' 772*b7893ccfSSadaf Ebrahimi paramdecl += '}\n' 773*b7893ccfSSadaf Ebrahimi else: 774*b7893ccfSSadaf Ebrahimi # externsync can list members to synchronize 775*b7893ccfSSadaf Ebrahimi for member in externsync.split(","): 776*b7893ccfSSadaf Ebrahimi member = str(member).replace("::", "->") 777*b7893ccfSSadaf Ebrahimi member = str(member).replace(".", "->") 778*b7893ccfSSadaf Ebrahimi paramdecl += ' ' + functionprefix + 'WriteObject(' + member + ');\n' 779*b7893ccfSSadaf Ebrahimi else: 780*b7893ccfSSadaf Ebrahimi paramtype = param.find('type') 781*b7893ccfSSadaf Ebrahimi if paramtype is not None: 782*b7893ccfSSadaf Ebrahimi paramtype = paramtype.text 783*b7893ccfSSadaf Ebrahimi else: 784*b7893ccfSSadaf Ebrahimi paramtype = 'None' 785*b7893ccfSSadaf Ebrahimi if paramtype in self.handle_types and paramtype != 'VkPhysicalDevice': 786*b7893ccfSSadaf Ebrahimi if self.paramIsArray(param) and ('pPipelines' != paramname.text): 787*b7893ccfSSadaf Ebrahimi # Add pointer dereference for array counts that are pointer values 788*b7893ccfSSadaf Ebrahimi dereference = '' 789*b7893ccfSSadaf Ebrahimi for candidate in params: 790*b7893ccfSSadaf Ebrahimi if param.attrib.get('len') == candidate.find('name').text: 791*b7893ccfSSadaf Ebrahimi if self.paramIsPointer(candidate): 792*b7893ccfSSadaf Ebrahimi dereference = '*' 793*b7893ccfSSadaf Ebrahimi param_len = str(param.attrib.get('len')).replace("::", "->") 794*b7893ccfSSadaf Ebrahimi paramdecl += 'if (' + paramname.text + ') {\n' 795*b7893ccfSSadaf Ebrahimi paramdecl += ' for (uint32_t index = 0; index < ' + dereference + param_len + '; index++) {\n' 796*b7893ccfSSadaf Ebrahimi paramdecl += ' ' + functionprefix + 'ReadObject(' + paramname.text + '[index]);\n' 797*b7893ccfSSadaf Ebrahimi paramdecl += ' }\n' 798*b7893ccfSSadaf Ebrahimi paramdecl += '}\n' 799*b7893ccfSSadaf Ebrahimi elif not self.paramIsPointer(param): 800*b7893ccfSSadaf Ebrahimi # Pointer params are often being created. 801*b7893ccfSSadaf Ebrahimi # They are not being read from. 802*b7893ccfSSadaf Ebrahimi paramdecl += functionprefix + 'ReadObject(' + paramname.text + ');\n' 803*b7893ccfSSadaf Ebrahimi explicitexternsyncparams = cmd.findall("param[@externsync]") 804*b7893ccfSSadaf Ebrahimi if (explicitexternsyncparams is not None): 805*b7893ccfSSadaf Ebrahimi for param in explicitexternsyncparams: 806*b7893ccfSSadaf Ebrahimi externsyncattrib = param.attrib.get('externsync') 807*b7893ccfSSadaf Ebrahimi paramname = param.find('name') 808*b7893ccfSSadaf Ebrahimi paramdecl += '// Host access to ' 809*b7893ccfSSadaf Ebrahimi if externsyncattrib == 'true': 810*b7893ccfSSadaf Ebrahimi if self.paramIsArray(param): 811*b7893ccfSSadaf Ebrahimi paramdecl += 'each member of ' + paramname.text 812*b7893ccfSSadaf Ebrahimi elif self.paramIsPointer(param): 813*b7893ccfSSadaf Ebrahimi paramdecl += 'the object referenced by ' + paramname.text 814*b7893ccfSSadaf Ebrahimi else: 815*b7893ccfSSadaf Ebrahimi paramdecl += paramname.text 816*b7893ccfSSadaf Ebrahimi else: 817*b7893ccfSSadaf Ebrahimi paramdecl += externsyncattrib 818*b7893ccfSSadaf Ebrahimi paramdecl += ' must be externally synchronized\n' 819*b7893ccfSSadaf Ebrahimi 820*b7893ccfSSadaf Ebrahimi # Find and add any "implicit" parameters that are thread unsafe 821*b7893ccfSSadaf Ebrahimi implicitexternsyncparams = cmd.find('implicitexternsyncparams') 822*b7893ccfSSadaf Ebrahimi if (implicitexternsyncparams is not None): 823*b7893ccfSSadaf Ebrahimi for elem in implicitexternsyncparams: 824*b7893ccfSSadaf Ebrahimi paramdecl += '// ' 825*b7893ccfSSadaf Ebrahimi paramdecl += elem.text 826*b7893ccfSSadaf Ebrahimi paramdecl += ' must be externally synchronized between host accesses\n' 827*b7893ccfSSadaf Ebrahimi 828*b7893ccfSSadaf Ebrahimi if (paramdecl == ''): 829*b7893ccfSSadaf Ebrahimi return None 830*b7893ccfSSadaf Ebrahimi else: 831*b7893ccfSSadaf Ebrahimi return paramdecl 832*b7893ccfSSadaf Ebrahimi def beginFile(self, genOpts): 833*b7893ccfSSadaf Ebrahimi OutputGenerator.beginFile(self, genOpts) 834*b7893ccfSSadaf Ebrahimi 835*b7893ccfSSadaf Ebrahimi # Initialize members that require the tree 836*b7893ccfSSadaf Ebrahimi self.handle_types = GetHandleTypes(self.registry.tree) 837*b7893ccfSSadaf Ebrahimi 838*b7893ccfSSadaf Ebrahimi # TODO: LUGMAL -- remove this and add our copyright 839*b7893ccfSSadaf Ebrahimi # User-supplied prefix text, if any (list of strings) 840*b7893ccfSSadaf Ebrahimi write(self.inline_copyright_message, file=self.outFile) 841*b7893ccfSSadaf Ebrahimi 842*b7893ccfSSadaf Ebrahimi self.header_file = (genOpts.filename == 'thread_safety.h') 843*b7893ccfSSadaf Ebrahimi self.source_file = (genOpts.filename == 'thread_safety.cpp') 844*b7893ccfSSadaf Ebrahimi 845*b7893ccfSSadaf Ebrahimi if not self.header_file and not self.source_file: 846*b7893ccfSSadaf Ebrahimi print("Error: Output Filenames have changed, update generator source.\n") 847*b7893ccfSSadaf Ebrahimi sys.exit(1) 848*b7893ccfSSadaf Ebrahimi 849*b7893ccfSSadaf Ebrahimi if self.source_file: 850*b7893ccfSSadaf Ebrahimi write('#include "chassis.h"', file=self.outFile) 851*b7893ccfSSadaf Ebrahimi write('#include "thread_safety.h"', file=self.outFile) 852*b7893ccfSSadaf Ebrahimi self.newline() 853*b7893ccfSSadaf Ebrahimi write(self.inline_custom_source_preamble, file=self.outFile) 854*b7893ccfSSadaf Ebrahimi 855*b7893ccfSSadaf Ebrahimi 856*b7893ccfSSadaf Ebrahimi def endFile(self): 857*b7893ccfSSadaf Ebrahimi 858*b7893ccfSSadaf Ebrahimi # Create class definitions 859*b7893ccfSSadaf Ebrahimi counter_class_defs = '' 860*b7893ccfSSadaf Ebrahimi counter_class_instances = '' 861*b7893ccfSSadaf Ebrahimi counter_class_bodies = '' 862*b7893ccfSSadaf Ebrahimi 863*b7893ccfSSadaf Ebrahimi for obj in sorted(self.non_dispatchable_types): 864*b7893ccfSSadaf Ebrahimi counter_class_defs += ' counter<%s> c_%s;\n' % (obj, obj) 865*b7893ccfSSadaf Ebrahimi if obj in self.object_to_debug_report_type: 866*b7893ccfSSadaf Ebrahimi obj_type = self.object_to_debug_report_type[obj] 867*b7893ccfSSadaf Ebrahimi else: 868*b7893ccfSSadaf Ebrahimi obj_type = 'VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT' 869*b7893ccfSSadaf Ebrahimi counter_class_instances += ' c_%s("%s", %s, &report_data),\n' % (obj, obj, obj_type) 870*b7893ccfSSadaf Ebrahimi counter_class_bodies += 'WRAPPER(%s)\n' % obj 871*b7893ccfSSadaf Ebrahimi if self.header_file: 872*b7893ccfSSadaf Ebrahimi class_def = self.inline_custom_header_preamble.replace('COUNTER_CLASS_DEFINITIONS_TEMPLATE', counter_class_defs) 873*b7893ccfSSadaf Ebrahimi class_def = class_def.replace('COUNTER_CLASS_INSTANCES_TEMPLATE', counter_class_instances[:-2]) # Kill last comma 874*b7893ccfSSadaf Ebrahimi class_def = class_def.replace('COUNTER_CLASS_BODIES_TEMPLATE', counter_class_bodies) 875*b7893ccfSSadaf Ebrahimi write(class_def, file=self.outFile) 876*b7893ccfSSadaf Ebrahimi write('\n'.join(self.sections['command']), file=self.outFile) 877*b7893ccfSSadaf Ebrahimi if self.header_file: 878*b7893ccfSSadaf Ebrahimi write('};', file=self.outFile) 879*b7893ccfSSadaf Ebrahimi 880*b7893ccfSSadaf Ebrahimi # Finish processing in superclass 881*b7893ccfSSadaf Ebrahimi OutputGenerator.endFile(self) 882*b7893ccfSSadaf Ebrahimi 883*b7893ccfSSadaf Ebrahimi def beginFeature(self, interface, emit): 884*b7893ccfSSadaf Ebrahimi #write('// starting beginFeature', file=self.outFile) 885*b7893ccfSSadaf Ebrahimi # Start processing in superclass 886*b7893ccfSSadaf Ebrahimi OutputGenerator.beginFeature(self, interface, emit) 887*b7893ccfSSadaf Ebrahimi # C-specific 888*b7893ccfSSadaf Ebrahimi # Accumulate includes, defines, types, enums, function pointer typedefs, 889*b7893ccfSSadaf Ebrahimi # end function prototypes separately for this feature. They're only 890*b7893ccfSSadaf Ebrahimi # printed in endFeature(). 891*b7893ccfSSadaf Ebrahimi self.featureExtraProtect = GetFeatureProtect(interface) 892*b7893ccfSSadaf Ebrahimi if (self.featureExtraProtect is not None): 893*b7893ccfSSadaf Ebrahimi self.appendSection('command', '\n#ifdef %s' % self.featureExtraProtect) 894*b7893ccfSSadaf Ebrahimi 895*b7893ccfSSadaf Ebrahimi #write('// ending beginFeature', file=self.outFile) 896*b7893ccfSSadaf Ebrahimi def endFeature(self): 897*b7893ccfSSadaf Ebrahimi # C-specific 898*b7893ccfSSadaf Ebrahimi if (self.emit): 899*b7893ccfSSadaf Ebrahimi if (self.featureExtraProtect is not None): 900*b7893ccfSSadaf Ebrahimi self.appendSection('command', '#endif // %s' % self.featureExtraProtect) 901*b7893ccfSSadaf Ebrahimi # Finish processing in superclass 902*b7893ccfSSadaf Ebrahimi OutputGenerator.endFeature(self) 903*b7893ccfSSadaf Ebrahimi # 904*b7893ccfSSadaf Ebrahimi # Append a definition to the specified section 905*b7893ccfSSadaf Ebrahimi def appendSection(self, section, text): 906*b7893ccfSSadaf Ebrahimi self.sections[section].append(text) 907*b7893ccfSSadaf Ebrahimi # 908*b7893ccfSSadaf Ebrahimi # Type generation 909*b7893ccfSSadaf Ebrahimi def genType(self, typeinfo, name, alias): 910*b7893ccfSSadaf Ebrahimi OutputGenerator.genType(self, typeinfo, name, alias) 911*b7893ccfSSadaf Ebrahimi if self.handle_types.IsNonDispatchable(name): 912*b7893ccfSSadaf Ebrahimi self.non_dispatchable_types.add(name) 913*b7893ccfSSadaf Ebrahimi # 914*b7893ccfSSadaf Ebrahimi # Struct (e.g. C "struct" type) generation. 915*b7893ccfSSadaf Ebrahimi # This is a special case of the <type> tag where the contents are 916*b7893ccfSSadaf Ebrahimi # interpreted as a set of <member> tags instead of freeform C 917*b7893ccfSSadaf Ebrahimi # C type declarations. The <member> tags are just like <param> 918*b7893ccfSSadaf Ebrahimi # tags - they are a declaration of a struct or union member. 919*b7893ccfSSadaf Ebrahimi # Only simple member declarations are supported (no nested 920*b7893ccfSSadaf Ebrahimi # structs etc.) 921*b7893ccfSSadaf Ebrahimi def genStruct(self, typeinfo, typeName, alias): 922*b7893ccfSSadaf Ebrahimi OutputGenerator.genStruct(self, typeinfo, typeName, alias) 923*b7893ccfSSadaf Ebrahimi body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n' 924*b7893ccfSSadaf Ebrahimi # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam) 925*b7893ccfSSadaf Ebrahimi for member in typeinfo.elem.findall('.//member'): 926*b7893ccfSSadaf Ebrahimi body += self.makeCParamDecl(member, self.genOpts.alignFuncParam) 927*b7893ccfSSadaf Ebrahimi body += ';\n' 928*b7893ccfSSadaf Ebrahimi body += '} ' + typeName + ';\n' 929*b7893ccfSSadaf Ebrahimi self.appendSection('struct', body) 930*b7893ccfSSadaf Ebrahimi # 931*b7893ccfSSadaf Ebrahimi # Group (e.g. C "enum" type) generation. 932*b7893ccfSSadaf Ebrahimi # These are concatenated together with other types. 933*b7893ccfSSadaf Ebrahimi def genGroup(self, groupinfo, groupName, alias): 934*b7893ccfSSadaf Ebrahimi pass 935*b7893ccfSSadaf Ebrahimi # Enumerant generation 936*b7893ccfSSadaf Ebrahimi # <enum> tags may specify their values in several ways, but are usually 937*b7893ccfSSadaf Ebrahimi # just integers. 938*b7893ccfSSadaf Ebrahimi def genEnum(self, enuminfo, name, alias): 939*b7893ccfSSadaf Ebrahimi pass 940*b7893ccfSSadaf Ebrahimi # 941*b7893ccfSSadaf Ebrahimi # Command generation 942*b7893ccfSSadaf Ebrahimi def genCmd(self, cmdinfo, name, alias): 943*b7893ccfSSadaf Ebrahimi # Commands shadowed by interface functions and are not implemented 944*b7893ccfSSadaf Ebrahimi special_functions = [ 945*b7893ccfSSadaf Ebrahimi 'vkCreateDevice', 946*b7893ccfSSadaf Ebrahimi 'vkCreateInstance', 947*b7893ccfSSadaf Ebrahimi 'vkAllocateCommandBuffers', 948*b7893ccfSSadaf Ebrahimi 'vkFreeCommandBuffers', 949*b7893ccfSSadaf Ebrahimi 'vkResetCommandPool', 950*b7893ccfSSadaf Ebrahimi 'vkDestroyCommandPool', 951*b7893ccfSSadaf Ebrahimi 'vkAllocateDescriptorSets', 952*b7893ccfSSadaf Ebrahimi 'vkQueuePresentKHR', 953*b7893ccfSSadaf Ebrahimi 'vkGetSwapchainImagesKHR', 954*b7893ccfSSadaf Ebrahimi ] 955*b7893ccfSSadaf Ebrahimi if name == 'vkQueuePresentKHR' or (name in special_functions and self.source_file): 956*b7893ccfSSadaf Ebrahimi return 957*b7893ccfSSadaf Ebrahimi 958*b7893ccfSSadaf Ebrahimi if (("DebugMarker" in name or "DebugUtilsObject" in name) and "EXT" in name): 959*b7893ccfSSadaf Ebrahimi self.appendSection('command', '// TODO - not wrapping EXT function ' + name) 960*b7893ccfSSadaf Ebrahimi return 961*b7893ccfSSadaf Ebrahimi 962*b7893ccfSSadaf Ebrahimi # Determine first if this function needs to be intercepted 963*b7893ccfSSadaf Ebrahimi startthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'Start') 964*b7893ccfSSadaf Ebrahimi if startthreadsafety is None: 965*b7893ccfSSadaf Ebrahimi return 966*b7893ccfSSadaf Ebrahimi finishthreadsafety = self.makeThreadUseBlock(cmdinfo.elem, 'Finish') 967*b7893ccfSSadaf Ebrahimi 968*b7893ccfSSadaf Ebrahimi OutputGenerator.genCmd(self, cmdinfo, name, alias) 969*b7893ccfSSadaf Ebrahimi 970*b7893ccfSSadaf Ebrahimi # setup common to call wrappers 971*b7893ccfSSadaf Ebrahimi # first parameter is always dispatchable 972*b7893ccfSSadaf Ebrahimi dispatchable_type = cmdinfo.elem.find('param/type').text 973*b7893ccfSSadaf Ebrahimi dispatchable_name = cmdinfo.elem.find('param/name').text 974*b7893ccfSSadaf Ebrahimi 975*b7893ccfSSadaf Ebrahimi decls = self.makeCDecls(cmdinfo.elem) 976*b7893ccfSSadaf Ebrahimi 977*b7893ccfSSadaf Ebrahimi result_type = cmdinfo.elem.find('proto/type') 978*b7893ccfSSadaf Ebrahimi 979*b7893ccfSSadaf Ebrahimi if self.source_file: 980*b7893ccfSSadaf Ebrahimi pre_decl = decls[0][:-1] 981*b7893ccfSSadaf Ebrahimi pre_decl = pre_decl.split("VKAPI_CALL ")[1] 982*b7893ccfSSadaf Ebrahimi pre_decl = 'void ThreadSafety::PreCallRecord' + pre_decl + ' {' 983*b7893ccfSSadaf Ebrahimi 984*b7893ccfSSadaf Ebrahimi # PreCallRecord 985*b7893ccfSSadaf Ebrahimi self.appendSection('command', '') 986*b7893ccfSSadaf Ebrahimi self.appendSection('command', pre_decl) 987*b7893ccfSSadaf Ebrahimi self.appendSection('command', " " + "\n ".join(str(startthreadsafety).rstrip().split("\n"))) 988*b7893ccfSSadaf Ebrahimi self.appendSection('command', '}') 989*b7893ccfSSadaf Ebrahimi 990*b7893ccfSSadaf Ebrahimi # PostCallRecord 991*b7893ccfSSadaf Ebrahimi post_decl = pre_decl.replace('PreCallRecord', 'PostCallRecord') 992*b7893ccfSSadaf Ebrahimi if result_type.text == 'VkResult': 993*b7893ccfSSadaf Ebrahimi post_decl = post_decl.replace(')', ',\n VkResult result)') 994*b7893ccfSSadaf Ebrahimi self.appendSection('command', '') 995*b7893ccfSSadaf Ebrahimi self.appendSection('command', post_decl) 996*b7893ccfSSadaf Ebrahimi self.appendSection('command', " " + "\n ".join(str(finishthreadsafety).rstrip().split("\n"))) 997*b7893ccfSSadaf Ebrahimi self.appendSection('command', '}') 998*b7893ccfSSadaf Ebrahimi 999*b7893ccfSSadaf Ebrahimi if self.header_file: 1000*b7893ccfSSadaf Ebrahimi pre_decl = decls[0][:-1] 1001*b7893ccfSSadaf Ebrahimi pre_decl = pre_decl.split("VKAPI_CALL ")[1] 1002*b7893ccfSSadaf Ebrahimi pre_decl = 'void PreCallRecord' + pre_decl + ';' 1003*b7893ccfSSadaf Ebrahimi 1004*b7893ccfSSadaf Ebrahimi # PreCallRecord 1005*b7893ccfSSadaf Ebrahimi self.appendSection('command', '') 1006*b7893ccfSSadaf Ebrahimi self.appendSection('command', pre_decl) 1007*b7893ccfSSadaf Ebrahimi 1008*b7893ccfSSadaf Ebrahimi # PostCallRecord 1009*b7893ccfSSadaf Ebrahimi post_decl = pre_decl.replace('PreCallRecord', 'PostCallRecord') 1010*b7893ccfSSadaf Ebrahimi if result_type.text == 'VkResult': 1011*b7893ccfSSadaf Ebrahimi post_decl = post_decl.replace(')', ',\n VkResult result)') 1012*b7893ccfSSadaf Ebrahimi self.appendSection('command', '') 1013*b7893ccfSSadaf Ebrahimi self.appendSection('command', post_decl) 1014*b7893ccfSSadaf Ebrahimi 1015*b7893ccfSSadaf Ebrahimi # 1016*b7893ccfSSadaf Ebrahimi # override makeProtoName to drop the "vk" prefix 1017*b7893ccfSSadaf Ebrahimi def makeProtoName(self, name, tail): 1018*b7893ccfSSadaf Ebrahimi return self.genOpts.apientry + name[2:] + tail 1019