tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

navigator_gpu.js (6624B)


      1 /**
      2 * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
      3 **/import { globalTestConfig } from '../framework/test_config.js';
      4 
      5 import { ErrorWithExtra, assert, hasFeature, objectEquals } from './util.js';
      6 
      7 /**
      8 * Finds and returns the `navigator.gpu` object (or equivalent, for non-browser implementations).
      9 * Throws an exception if not found.
     10 */
     11 function defaultGPUProvider() {
     12  assert(
     13    typeof navigator !== 'undefined' && navigator.gpu !== undefined,
     14    'No WebGPU implementation found'
     15  );
     16  return navigator.gpu;
     17 }
     18 
     19 /**
     20 * GPUProvider is a function that creates and returns a new GPU instance.
     21 * May throw an exception if a GPU cannot be created.
     22 */
     23 
     24 
     25 let gpuProvider = defaultGPUProvider;
     26 
     27 /**
     28 * Sets the function to create and return a new GPU instance.
     29 */
     30 export function setGPUProvider(provider) {
     31  assert(impl === undefined, 'setGPUProvider() should not be after getGPU()');
     32  gpuProvider = provider;
     33 }
     34 
     35 let impl = undefined;
     36 let s_defaultLimits = undefined;
     37 
     38 let defaultRequestAdapterOptions;
     39 
     40 export function setDefaultRequestAdapterOptions(options) {
     41  // It's okay to call this if you don't change the options
     42  if (objectEquals(options, defaultRequestAdapterOptions)) {
     43    return;
     44  }
     45  if (impl) {
     46    throw new Error('must call setDefaultRequestAdapterOptions before getGPU');
     47  }
     48  defaultRequestAdapterOptions = { ...options };
     49 }
     50 
     51 export function getDefaultRequestAdapterOptions() {
     52  return defaultRequestAdapterOptions;
     53 }
     54 
     55 function copyLimits(objLike) {
     56  const obj = {};
     57  for (const key in objLike) {
     58    obj[key] = objLike[key];
     59  }
     60  return obj;
     61 }
     62 
     63 /**
     64 * Finds and returns the `navigator.gpu` object (or equivalent, for non-browser implementations).
     65 * Throws an exception if not found.
     66 */
     67 export function getGPU(recorder) {
     68  if (impl) {
     69    return impl;
     70  }
     71 
     72  impl = gpuProvider();
     73 
     74  if (globalTestConfig.enforceDefaultLimits) {
     75 
     76    const origRequestAdapterFn = impl.requestAdapter;
     77 
     78    const origRequestDeviceFn = GPUAdapter.prototype.requestDevice;
     79 
     80    Object.defineProperty(impl, 'requestAdapter', {
     81      configurable: true,
     82      async value(options) {
     83        if (!s_defaultLimits) {
     84          const tempAdapter = await origRequestAdapterFn.call(this, {
     85            ...defaultRequestAdapterOptions,
     86            ...options
     87          });
     88 
     89          const tempDevice = await tempAdapter?.requestDevice();
     90          s_defaultLimits = copyLimits(tempDevice.limits);
     91          tempDevice?.destroy();
     92        }
     93        const adapter = await origRequestAdapterFn.call(this, {
     94          ...defaultRequestAdapterOptions,
     95          ...options
     96        });
     97        if (adapter) {
     98          const limits = Object.fromEntries(
     99            Object.entries(s_defaultLimits).map(([key, v]) => [key, v])
    100          );
    101 
    102          Object.defineProperty(adapter, 'limits', {
    103            get() {
    104              return limits;
    105            }
    106          });
    107        }
    108        return adapter;
    109      }
    110    });
    111 
    112    const enforceDefaultLimits = (adapter, desc) => {
    113      if (desc?.requiredLimits) {
    114        for (const [key, value] of Object.entries(desc.requiredLimits)) {
    115          const limit = s_defaultLimits[key];
    116          if (limit !== undefined && value !== undefined) {
    117            const [beyondLimit, condition] = key.startsWith('max') ?
    118            [value > limit, 'greater'] :
    119            [value < limit, 'less'];
    120            if (beyondLimit) {
    121              throw new DOMException(
    122                `requestedLimit ${value} for ${key} is ${condition} than adapter limit ${limit}`,
    123                'OperationError'
    124              );
    125            }
    126          }
    127        }
    128      }
    129    };
    130 
    131    GPUAdapter.prototype.requestDevice = async function (
    132 
    133    desc)
    134    {
    135      // We need to enforce the default limits because even though we patched the adapter to
    136      // show defaults for adapter.limits, there are tests that test we throw when we request more than the max.
    137      // In other words.
    138      //
    139      //   adapter.requestDevice({ requiredLimits: {
    140      //     maxXXX: adapter.limits.maxXXX + 1,  // should throw
    141      //   });
    142      //
    143      // But unless we enforce this manually, it won't actually throw if the adapter's
    144      // true limits are higher than we patched above.
    145      enforceDefaultLimits(this, desc);
    146      return await origRequestDeviceFn.call(this, desc);
    147    };
    148  }
    149 
    150  if (globalTestConfig.blockAllFeatures) {
    151 
    152    const origRequestAdapterFn = impl.requestAdapter;
    153 
    154    const origRequestDeviceFn = GPUAdapter.prototype.requestDevice;
    155 
    156    Object.defineProperty(impl, 'requestAdapter', {
    157      configurable: true,
    158      async value(options) {
    159        const adapter = await origRequestAdapterFn.call(this, {
    160          ...defaultRequestAdapterOptions,
    161          ...options
    162        });
    163        if (adapter) {
    164          Object.defineProperty(adapter, 'features', {
    165            enumerable: false,
    166            value: new Set(
    167              hasFeature(adapter.features, 'core-features-and-limits') ?
    168              ['core-features-and-limits'] :
    169              []
    170            )
    171          });
    172        }
    173        return adapter;
    174      }
    175    });
    176 
    177    const enforceBlockedFeatures = (adapter, desc) => {
    178      if (desc?.requiredFeatures) {
    179        for (const [feature] of desc.requiredFeatures) {
    180          // Note: This adapter has had its features property over-ridden and will only return
    181          // have nothing or 'core-features-and-limits'.
    182 
    183          if (!adapter.features.has(feature)) {
    184            throw new TypeError(`requested feature ${feature} does not exist on adapter`);
    185          }
    186        }
    187      }
    188    };
    189 
    190    GPUAdapter.prototype.requestDevice = async function (
    191 
    192    desc)
    193    {
    194      // We need to enforce the feature block because even though we patched the adapter to
    195      // advertise no features they still exist on the real adapter.
    196      enforceBlockedFeatures(this, desc);
    197      return await origRequestDeviceFn.call(this, desc);
    198    };
    199  }
    200 
    201  if (defaultRequestAdapterOptions) {
    202 
    203    const origRequestAdapterFn = impl.requestAdapter;
    204 
    205 
    206    Object.defineProperty(impl, 'requestAdapter', {
    207      configurable: true,
    208      async value(options) {
    209        const adapter = await origRequestAdapterFn.call(this, {
    210          ...defaultRequestAdapterOptions,
    211          ...options
    212        });
    213        if (recorder && adapter) {
    214          const adapterInfo = adapter.info;
    215          const infoString = `Adapter: ${adapterInfo.vendor} / ${adapterInfo.architecture} / ${adapterInfo.device}`;
    216          recorder.debug(new ErrorWithExtra(infoString, () => ({ adapterInfo })));
    217        }
    218        return adapter;
    219      }
    220    });
    221  }
    222 
    223  return impl;
    224 }