Skip to content

Commit

Permalink
Add preferLowPower param to CreateDevice (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
flibitijibibo committed Jul 19, 2024
1 parent b903845 commit 73395b9
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 15 deletions.
4 changes: 3 additions & 1 deletion include/SDL3/SDL_gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,7 @@ typedef struct SDL_GpuStorageTextureReadWriteBinding
*
* \param preferredBackends a bitflag containing the renderers most recognized by the application
* \param debugMode enable debug mode properties and validations
* \param preferLowPower set this to SDL_TRUE if your app prefers energy efficiency over maximum GPU performance
* \returns a GPU context on success or NULL on failure
*
* \since This function is available since SDL 3.x.x
Expand All @@ -799,7 +800,8 @@ typedef struct SDL_GpuStorageTextureReadWriteBinding
*/
extern SDL_DECLSPEC SDL_GpuDevice *SDLCALL SDL_GpuCreateDevice(
SDL_GpuBackend preferredBackends,
SDL_bool debugMode);
SDL_bool debugMode,
SDL_bool preferLowPower);

/**
* Destroys a GPU context previously returned by SDL_GpuCreateDevice.
Expand Down
2 changes: 1 addition & 1 deletion src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1082,7 +1082,7 @@ SDL_DYNAPI_PROC(size_t,SDL_wcsnlen,(const wchar_t *a, size_t b),(a,b),return)
SDL_DYNAPI_PROC(wchar_t*,SDL_wcsnstr,(const wchar_t *a, const wchar_t *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(wchar_t*,SDL_wcsstr,(const wchar_t *a, const wchar_t *b),(a,b),return)
SDL_DYNAPI_PROC(long,SDL_wcstol,(const wchar_t *a, wchar_t **b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_GpuDevice*,SDL_GpuCreateDevice,(SDL_GpuBackend a, SDL_bool b),(a,b),return)
SDL_DYNAPI_PROC(SDL_GpuDevice*,SDL_GpuCreateDevice,(SDL_GpuBackend a, SDL_bool b, SDL_bool c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_GpuDestroyDevice,(SDL_GpuDevice *a),(a),)
SDL_DYNAPI_PROC(SDL_GpuBackend,SDL_GpuGetBackend,(SDL_GpuDevice *a),(a),return)
SDL_DYNAPI_PROC(SDL_GpuComputePipeline*,SDL_GpuCreateComputePipeline,(SDL_GpuDevice *a, SDL_GpuComputePipelineCreateInfo *b),(a,b),return)
Expand Down
5 changes: 3 additions & 2 deletions src/gpu/SDL_gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ static SDL_GpuBackend SDL_GpuSelectBackend(SDL_VideoDevice *_this, SDL_GpuBacken

SDL_GpuDevice *SDL_GpuCreateDevice(
SDL_GpuBackend preferredBackends,
SDL_bool debugMode)
SDL_bool debugMode,
SDL_bool preferLowPower)
{
int i;
SDL_GpuDevice *result = NULL;
Expand All @@ -175,7 +176,7 @@ SDL_GpuDevice *SDL_GpuCreateDevice(
if (selectedBackend != SDL_GPU_BACKEND_INVALID) {
for (i = 0; backends[i]; i += 1) {
if (backends[i]->backendflag == selectedBackend) {
result = backends[i]->CreateDevice(debugMode);
result = backends[i]->CreateDevice(debugMode, preferLowPower);
if (result != NULL) {
result->backend = backends[i]->backendflag;
break;
Expand Down
2 changes: 1 addition & 1 deletion src/gpu/SDL_gpu_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ typedef struct SDL_GpuDriver
const char *Name;
const SDL_GpuBackend backendflag;
SDL_bool (*PrepareDriver)(SDL_VideoDevice *_this);
SDL_GpuDevice *(*CreateDevice)(SDL_bool debugMode);
SDL_GpuDevice *(*CreateDevice)(SDL_bool debugMode, SDL_bool preferLowPower);
} SDL_GpuDriver;

extern SDL_GpuDriver VulkanDriver;
Expand Down
6 changes: 4 additions & 2 deletions src/gpu/d3d11/SDL_gpu_d3d11.c
Original file line number Diff line number Diff line change
Expand Up @@ -6071,7 +6071,7 @@ static void D3D11_INTERNAL_DestroyBlitPipelines(
D3D11_ReleaseGraphicsPipeline(driverData, renderer->blitFrom2DArrayPipeline);
}

static SDL_GpuDevice *D3D11_CreateDevice(SDL_bool debugMode)
static SDL_GpuDevice *D3D11_CreateDevice(SDL_bool debugMode, SDL_bool preferLowPower)
{
D3D11Renderer *renderer;
PFN_CREATE_DXGI_FACTORY1 CreateDXGIFactoryFunc;
Expand Down Expand Up @@ -6159,7 +6159,9 @@ static SDL_GpuDevice *D3D11_CreateDevice(SDL_bool debugMode)
IDXGIFactory6_EnumAdapterByGpuPreference(
factory6,
0,
DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
preferLowPower ?
DXGI_GPU_PREFERENCE_MINIMUM_POWER :
DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
&D3D_IID_IDXGIAdapter1,
(void **)&renderer->adapter);
IDXGIFactory6_Release(factory6);
Expand Down
17 changes: 15 additions & 2 deletions src/gpu/metal/SDL_gpu_metal.m
Original file line number Diff line number Diff line change
Expand Up @@ -3839,15 +3839,28 @@ static void METAL_INTERNAL_DestroyBlitResources(
SDL_free(renderer->blitPipelines);
}

static SDL_GpuDevice *METAL_CreateDevice(SDL_bool debugMode)
static SDL_GpuDevice *METAL_CreateDevice(SDL_bool debugMode, SDL_bool preferLowPower)
{
MetalRenderer *renderer;

/* Allocate and zero out the renderer */
renderer = (MetalRenderer *)SDL_calloc(1, sizeof(MetalRenderer));

/* Create the Metal device and command queue */
renderer->device = MTLCreateSystemDefaultDevice();
#ifdef SDL_PLATFORM_MACOS
if (preferLowPower) {
NSArray<id<MTLDevice>> *devices = MTLCopyAllDevices();
for (id<MTLDevice> device in devices) {
if (device.isLowPower) {
renderer->device = device;
break;
}
}
}
#endif
if (renderer->device == NULL) {
renderer->device = MTLCreateSystemDefaultDevice();
}
renderer->queue = [renderer->device newCommandQueue];

/* Print driver info */
Expand Down
24 changes: 19 additions & 5 deletions src/gpu/vulkan/SDL_gpu_vulkan.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,22 @@ typedef struct VulkanExtensions

/* Conversions */

static const Uint8 DEVICE_PRIORITY[] = {
static const Uint8 DEVICE_PRIORITY_HIGHPERFORMANCE[] = {
0, /* VK_PHYSICAL_DEVICE_TYPE_OTHER */
3, /* VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU */
4, /* VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU */
2, /* VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU */
1 /* VK_PHYSICAL_DEVICE_TYPE_CPU */
};

static const Uint8 DEVICE_PRIORITY_LOWPOWER[] = {
0, /* VK_PHYSICAL_DEVICE_TYPE_OTHER */
4, /* VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU */
3, /* VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU */
2, /* VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU */
1 /* VK_PHYSICAL_DEVICE_TYPE_CPU */
};

static VkPresentModeKHR SDLToVK_PresentMode[] = {
VK_PRESENT_MODE_FIFO_KHR,
VK_PRESENT_MODE_IMMEDIATE_KHR,
Expand Down Expand Up @@ -1277,6 +1285,7 @@ struct VulkanRenderer
Uint8 outofBARMemoryWarning;

SDL_bool debugMode;
SDL_bool preferLowPower;
VulkanExtensions supports;
SDL_bool supportsDebugUtils;
SDL_bool supportsColorspace;
Expand Down Expand Up @@ -10978,21 +10987,25 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
VkPhysicalDeviceProperties deviceProperties;
Uint32 i;

const Uint8 *devicePriority = renderer->preferLowPower ?
DEVICE_PRIORITY_LOWPOWER :
DEVICE_PRIORITY_HIGHPERFORMANCE;

/* Get the device rank before doing any checks, in case one fails.
* Note: If no dedicated device exists, one that supports our features
* would be fine
*/
renderer->vkGetPhysicalDeviceProperties(
physicalDevice,
&deviceProperties);
if (*deviceRank < DEVICE_PRIORITY[deviceProperties.deviceType]) {
if (*deviceRank < devicePriority[deviceProperties.deviceType]) {
/* This device outranks the best device we've found so far!
* This includes a dedicated GPU that has less features than an
* integrated GPU, because this is a freak case that is almost
* never intentionally desired by the end user
*/
*deviceRank = DEVICE_PRIORITY[deviceProperties.deviceType];
} else if (*deviceRank > DEVICE_PRIORITY[deviceProperties.deviceType]) {
*deviceRank = devicePriority[deviceProperties.deviceType];
} else if (*deviceRank > devicePriority[deviceProperties.deviceType]) {
/* Device is outranked by a previous device, don't even try to
* run a query and reset the rank to avoid overwrites
*/
Expand Down Expand Up @@ -11457,7 +11470,7 @@ static SDL_bool VULKAN_PrepareDriver(SDL_VideoDevice *_this)
return result;
}

static SDL_GpuDevice *VULKAN_CreateDevice(SDL_bool debugMode)
static SDL_GpuDevice *VULKAN_CreateDevice(SDL_bool debugMode, SDL_bool preferLowPower)
{
VulkanRenderer *renderer;

Expand All @@ -11479,6 +11492,7 @@ static SDL_GpuDevice *VULKAN_CreateDevice(SDL_bool debugMode)
renderer = (VulkanRenderer *)SDL_malloc(sizeof(VulkanRenderer));
SDL_memset(renderer, '\0', sizeof(VulkanRenderer));
renderer->debugMode = debugMode;
renderer->preferLowPower = preferLowPower;

if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize Vulkan!");
Expand Down
2 changes: 1 addition & 1 deletion test/testgpu_spinning_cube.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ init_render_state(void)
SDL_GpuShader *fragment_shader;
int i;

gpu_device = SDL_GpuCreateDevice(SDL_GPU_BACKEND_ALL, 1);
gpu_device = SDL_GpuCreateDevice(SDL_GPU_BACKEND_ALL, 1, 0);
CHECK_CREATE(gpu_device, "GPU device");

/* Claim the windows */
Expand Down

0 comments on commit 73395b9

Please sign in to comment.