GPU: Add platform parameter for GPU architecture #112566

Merged
Clément Foucault merged 6 commits from Jason-Fielder/blender:GPUPlatformArchitectureParam into main 2023-09-28 12:50:05 +02:00
7 changed files with 52 additions and 7 deletions

View File

@ -55,6 +55,19 @@ typedef enum eGPUSupportLevel {
GPU_SUPPORT_LEVEL_UNSUPPORTED,
} eGPUSupportLevel;
typedef enum GPUArchitectureType {

do not use e prefix. This is from an older codestyle no longer in place.

do not use `e` prefix. This is from an older codestyle no longer in place.

Ah gotcha! Will update thanks, had originally just aimed to be consistent with the other Enums declared in this file.

Ah gotcha! Will update thanks, had originally just aimed to be consistent with the other Enums declared in this file.
/* Immediate Mode Renderer (IMR).

These terms are not clear.
If I look further in the code it is unified memory or not.

Think eGPUMemoryModel would be more appropriate as an GPU architecture is typically used to refer to a processor type or series. Possible values might be
GPU_MEMORY_MODEL_INTEGRATED
GPU_MEMORY_MODEL_DEDICATED
GPU_MEMORY_MODEL_UNIFIED

These terms are not clear. If I look further in the code it is unified memory or not. Think eGPUMemoryModel would be more appropriate as an GPU architecture is typically used to refer to a processor type or series. Possible values might be GPU_MEMORY_MODEL_INTEGRATED GPU_MEMORY_MODEL_DEDICATED GPU_MEMORY_MODEL_UNIFIED

I think it is more about the way how the chip is build to render. So it has nothing to do with the memory model. Some intel chip might have some dedicated memory but still work as tile renderer.

I think it is more about the way how the chip is build to render. So it has nothing to do with the memory model. Some intel chip might have some dedicated memory but still work as tile renderer.

The memory model would also likely be a valid capability to expose, but would cover different use-cases.

Currently, the use-case for architecture type would be to determine which implementation of virtual shadow map updating to use as per: #111283 (Metal: EEVEE Next: Optimize Virtual shadow maps for Apple Silicon).

Granted, the memory model could be used to achieve the same switch, but the implementation of the technique is mostly depending on the architecture style of the GPU, as Clement outlined.

It could still theoretically be possible to have either type of architecture with any other type of memory model.

This architecture check may also be relevant for other APIs in future, especially also for windows machines running with Qualcomm Snapdragon GPUs. (Qualcomm is also a little iffy as technically these GPUs can also run in immediate mode, depending on the bits-per-pixel and workload being rendered)

Perhaps it's a technicality atm, as atm, there is a correlation between tile-based architectures and system-on-chip Unified memory architecture, so I guess it depends which parameter best represents this.

I see two options:

  1. Add both capabilities
  2. Use eGPUMemoryModel with the assumption that a unified memory implies a tile-based renderer, which can use tile-shaders and on-tile per-pixel storage.
The memory model would also likely be a valid capability to expose, but would cover different use-cases. Currently, the use-case for architecture type would be to determine which implementation of virtual shadow map updating to use as per: https://projects.blender.org/blender/blender/pulls/111283 (Metal: EEVEE Next: Optimize Virtual shadow maps for Apple Silicon). Granted, the memory model could be used to achieve the same switch, but the implementation of the technique is mostly depending on the architecture style of the GPU, as Clement outlined. It could still theoretically be possible to have either type of architecture with any other type of memory model. This architecture check may also be relevant for other APIs in future, especially also for windows machines running with Qualcomm Snapdragon GPUs. (Qualcomm is also a little iffy as technically these GPUs can also run in immediate mode, depending on the bits-per-pixel and workload being rendered) Perhaps it's a technicality atm, as atm, there is a correlation between tile-based architectures and system-on-chip Unified memory architecture, so I guess it depends which parameter best represents this. I see two options: 1) Add both capabilities 2) Use eGPUMemoryModel with the assumption that a unified memory implies a tile-based renderer, which can use tile-shaders and on-tile per-pixel storage.

In that case it makes more sense to have a GPU capability setting where we can check if it uses tiled rendering. As this is still an internal property think it is enough to use a bool.
GPU_tiled_renderer_support() or something similar.

In that case it makes more sense to have a GPU capability setting where we can check if it uses tiled rendering. As this is still an internal property think it is enough to use a bool. `GPU_tiled_renderer_support()` or something similar.
* Typically, an IMR architecture will execute GPU work in sequence, rasterizing primitives in
* order. */
GPU_ARCHITECTURE_IMR = 0,
/* Tile-Based-Deferred-Renderer (TBDR).
* A TBDR architecture will typically execute the vertex stage up-front for all primitives,
* binning geometry into distinct tiled regions. Fragments will then be rasterized within
* the bounds of one tile at a time. */
GPU_ARCHITECTURE_TBDR = 1,
} GPUArchitectureType;
#ifdef __cplusplus
extern "C" {
#endif
@ -74,6 +87,7 @@ const char *GPU_platform_renderer(void);
const char *GPU_platform_version(void);
const char *GPU_platform_support_level_key(void);
const char *GPU_platform_gpu_name(void);
GPUArchitectureType GPU_platform_architecture(void);
#ifdef __cplusplus
}

View File

@ -30,7 +30,8 @@ class DummyBackend : public GPUBackend {
GPU_BACKEND_NONE,
"Unknown",
"",
"");
"",
GPU_ARCHITECTURE_IMR);
}
void delete_resources() override {}
void samplers_update() override {}

View File

@ -70,7 +70,8 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
eGPUBackendType backend,
const char *vendor_str,
const char *renderer_str,
const char *version_str)
const char *version_str,
GPUArchitectureType arch_type)
{
this->clear();
@ -91,6 +92,7 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
this->support_key = create_key(gpu_support_level, vendor, renderer, version);
this->gpu_name = create_gpu_name(vendor, renderer, version);
this->backend = backend;
this->architecture_type = arch_type;
}
void GPUPlatformGlobal::clear()
@ -149,6 +151,12 @@ const char *GPU_platform_gpu_name()
return GPG.gpu_name;
}
GPUArchitectureType GPU_platform_architecture()
{
BLI_assert(GPG.initialized);
return GPG.architecture_type;
}
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
{
return GPU_type_matches_ex(device, os, driver, GPU_BACKEND_ANY);

View File

@ -25,6 +25,7 @@ class GPUPlatformGlobal {
char *support_key = nullptr;
char *gpu_name = nullptr;
eGPUBackendType backend = GPU_BACKEND_NONE;
GPUArchitectureType architecture_type = GPU_ARCHITECTURE_IMR;
public:
void init(eGPUDeviceType gpu_device,
@ -34,7 +35,8 @@ class GPUPlatformGlobal {
eGPUBackendType backend,
const char *vendor_str,
const char *renderer_str,
const char *version_str);
const char *version_str,
GPUArchitectureType arch_type);
void clear();
};

View File

@ -194,6 +194,8 @@ void MTLBackend::platform_init(MTLContext *ctx)
if (G.debug & G_DEBUG_GPU) {
printf("METAL API - DETECTED GPU: %s\n", vendor);
}
GPUArchitectureType architecture_type = (mtl_device.hasUnifiedMemory) ? GPU_ARCHITECTURE_TBDR :
GPU_ARCHITECTURE_IMR;
/* macOS is the only supported platform, but check to ensure we are not building with Metal
* enablement on another platform. */
@ -240,7 +242,15 @@ void MTLBackend::platform_init(MTLContext *ctx)
printf("Renderer: %s\n", renderer);
}
GPG.init(device, os, driver, support_level, GPU_BACKEND_METAL, vendor, renderer, version);
GPG.init(device,
os,
driver,
support_level,
GPU_BACKEND_METAL,
vendor,
renderer,
version,
architecture_type);
}
void MTLBackend::platform_exit()

View File

@ -163,7 +163,15 @@ void GLBackend::platform_init()
}
}
GPG.init(device, os, driver, support_level, GPU_BACKEND_OPENGL, vendor, renderer, version);
GPG.init(device,
os,
driver,
support_level,
GPU_BACKEND_OPENGL,
vendor,
renderer,
version,
GPU_ARCHITECTURE_IMR);
}
void GLBackend::platform_exit()

View File

@ -50,7 +50,8 @@ void VKBackend::platform_init()
GPU_BACKEND_VULKAN,
"",
"",
"");
"",
GPU_ARCHITECTURE_IMR);
}
void VKBackend::platform_init(const VKDevice &device)
@ -72,7 +73,8 @@ void VKBackend::platform_init(const VKDevice &device)
GPU_BACKEND_VULKAN,
vendor_name.c_str(),
properties.deviceName,
driver_version.c_str());
driver_version.c_str(),
GPU_ARCHITECTURE_IMR);
}
void VKBackend::detect_workarounds(VKDevice &device)