Skip to content

Commit 06c561e

Browse files
Add preferLowPower param to CreateDevice (#72)
1 parent db917ee commit 06c561e

File tree

8 files changed

+47
-15
lines changed

8 files changed

+47
-15
lines changed

include/SDL3/SDL_gpu.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ typedef struct SDL_GpuStorageTextureReadWriteBinding
790790
*
791791
* \param preferredBackends a bitflag containing the renderers most recognized by the application
792792
* \param debugMode enable debug mode properties and validations
793+
* \param preferLowPower set this to SDL_TRUE if your app prefers energy efficiency over maximum GPU performance
793794
* \returns a GPU context on success or NULL on failure
794795
*
795796
* \since This function is available since SDL 3.x.x
@@ -799,7 +800,8 @@ typedef struct SDL_GpuStorageTextureReadWriteBinding
799800
*/
800801
extern SDL_DECLSPEC SDL_GpuDevice *SDLCALL SDL_GpuCreateDevice(
801802
SDL_GpuBackend preferredBackends,
802-
SDL_bool debugMode);
803+
SDL_bool debugMode,
804+
SDL_bool preferLowPower);
803805

804806
/**
805807
* Destroys a GPU context previously returned by SDL_GpuCreateDevice.

src/dynapi/SDL_dynapi_procs.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ SDL_DYNAPI_PROC(size_t,SDL_wcsnlen,(const wchar_t *a, size_t b),(a,b),return)
10661066
SDL_DYNAPI_PROC(wchar_t*,SDL_wcsnstr,(const wchar_t *a, const wchar_t *b, size_t c),(a,b,c),return)
10671067
SDL_DYNAPI_PROC(wchar_t*,SDL_wcsstr,(const wchar_t *a, const wchar_t *b),(a,b),return)
10681068
SDL_DYNAPI_PROC(long,SDL_wcstol,(const wchar_t *a, wchar_t **b, int c),(a,b,c),return)
1069-
SDL_DYNAPI_PROC(SDL_GpuDevice*,SDL_GpuCreateDevice,(SDL_GpuBackend a, SDL_bool b),(a,b),return)
1069+
SDL_DYNAPI_PROC(SDL_GpuDevice*,SDL_GpuCreateDevice,(SDL_GpuBackend a, SDL_bool b, SDL_bool c),(a,b,c),return)
10701070
SDL_DYNAPI_PROC(void,SDL_GpuDestroyDevice,(SDL_GpuDevice *a),(a),)
10711071
SDL_DYNAPI_PROC(SDL_GpuBackend,SDL_GpuGetBackend,(SDL_GpuDevice *a),(a),return)
10721072
SDL_DYNAPI_PROC(SDL_GpuComputePipeline*,SDL_GpuCreateComputePipeline,(SDL_GpuDevice *a, SDL_GpuComputePipelineCreateInfo *b),(a,b),return)

src/gpu/SDL_gpu.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ static SDL_GpuBackend SDL_GpuSelectBackend(SDL_VideoDevice *_this, SDL_GpuBacken
159159

160160
SDL_GpuDevice *SDL_GpuCreateDevice(
161161
SDL_GpuBackend preferredBackends,
162-
SDL_bool debugMode)
162+
SDL_bool debugMode,
163+
SDL_bool preferLowPower)
163164
{
164165
int i;
165166
SDL_GpuDevice *result = NULL;
@@ -175,7 +176,7 @@ SDL_GpuDevice *SDL_GpuCreateDevice(
175176
if (selectedBackend != SDL_GPU_BACKEND_INVALID) {
176177
for (i = 0; backends[i]; i += 1) {
177178
if (backends[i]->backendflag == selectedBackend) {
178-
result = backends[i]->CreateDevice(debugMode);
179+
result = backends[i]->CreateDevice(debugMode, preferLowPower);
179180
if (result != NULL) {
180181
result->backend = backends[i]->backendflag;
181182
break;

src/gpu/SDL_gpu_driver.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ typedef struct SDL_GpuDriver
687687
const char *Name;
688688
const SDL_GpuBackend backendflag;
689689
SDL_bool (*PrepareDriver)(SDL_VideoDevice *_this);
690-
SDL_GpuDevice *(*CreateDevice)(SDL_bool debugMode);
690+
SDL_GpuDevice *(*CreateDevice)(SDL_bool debugMode, SDL_bool preferLowPower);
691691
} SDL_GpuDriver;
692692

693693
extern SDL_GpuDriver VulkanDriver;

src/gpu/d3d11/SDL_gpu_d3d11.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -6071,7 +6071,7 @@ static void D3D11_INTERNAL_DestroyBlitPipelines(
60716071
D3D11_ReleaseGraphicsPipeline(driverData, renderer->blitFrom2DArrayPipeline);
60726072
}
60736073

6074-
static SDL_GpuDevice *D3D11_CreateDevice(SDL_bool debugMode)
6074+
static SDL_GpuDevice *D3D11_CreateDevice(SDL_bool debugMode, SDL_bool preferLowPower)
60756075
{
60766076
D3D11Renderer *renderer;
60776077
PFN_CREATE_DXGI_FACTORY1 CreateDXGIFactoryFunc;
@@ -6159,7 +6159,9 @@ static SDL_GpuDevice *D3D11_CreateDevice(SDL_bool debugMode)
61596159
IDXGIFactory6_EnumAdapterByGpuPreference(
61606160
factory6,
61616161
0,
6162-
DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
6162+
preferLowPower ?
6163+
DXGI_GPU_PREFERENCE_MINIMUM_POWER :
6164+
DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
61636165
&D3D_IID_IDXGIAdapter1,
61646166
(void **)&renderer->adapter);
61656167
IDXGIFactory6_Release(factory6);

src/gpu/metal/SDL_gpu_metal.m

+15-2
Original file line numberDiff line numberDiff line change
@@ -3839,15 +3839,28 @@ static void METAL_INTERNAL_DestroyBlitResources(
38393839
SDL_free(renderer->blitPipelines);
38403840
}
38413841

3842-
static SDL_GpuDevice *METAL_CreateDevice(SDL_bool debugMode)
3842+
static SDL_GpuDevice *METAL_CreateDevice(SDL_bool debugMode, SDL_bool preferLowPower)
38433843
{
38443844
MetalRenderer *renderer;
38453845

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

38493849
/* Create the Metal device and command queue */
3850-
renderer->device = MTLCreateSystemDefaultDevice();
3850+
#ifdef SDL_PLATFORM_MACOS
3851+
if (preferLowPower) {
3852+
NSArray<id<MTLDevice>> *devices = MTLCopyAllDevices();
3853+
for (id<MTLDevice> device in devices) {
3854+
if (device.isLowPower) {
3855+
renderer->device = device;
3856+
break;
3857+
}
3858+
}
3859+
}
3860+
#endif
3861+
if (renderer->device == NULL) {
3862+
renderer->device = MTLCreateSystemDefaultDevice();
3863+
}
38513864
renderer->queue = [renderer->device newCommandQueue];
38523865

38533866
/* Print driver info */

src/gpu/vulkan/SDL_gpu_vulkan.c

+19-5
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,22 @@ typedef struct VulkanExtensions
118118

119119
/* Conversions */
120120

121-
static const Uint8 DEVICE_PRIORITY[] = {
121+
static const Uint8 DEVICE_PRIORITY_HIGHPERFORMANCE[] = {
122122
0, /* VK_PHYSICAL_DEVICE_TYPE_OTHER */
123123
3, /* VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU */
124124
4, /* VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU */
125125
2, /* VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU */
126126
1 /* VK_PHYSICAL_DEVICE_TYPE_CPU */
127127
};
128128

129+
static const Uint8 DEVICE_PRIORITY_LOWPOWER[] = {
130+
0, /* VK_PHYSICAL_DEVICE_TYPE_OTHER */
131+
4, /* VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU */
132+
3, /* VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU */
133+
2, /* VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU */
134+
1 /* VK_PHYSICAL_DEVICE_TYPE_CPU */
135+
};
136+
129137
static VkPresentModeKHR SDLToVK_PresentMode[] = {
130138
VK_PRESENT_MODE_FIFO_KHR,
131139
VK_PRESENT_MODE_IMMEDIATE_KHR,
@@ -1277,6 +1285,7 @@ struct VulkanRenderer
12771285
Uint8 outofBARMemoryWarning;
12781286

12791287
SDL_bool debugMode;
1288+
SDL_bool preferLowPower;
12801289
VulkanExtensions supports;
12811290
SDL_bool supportsDebugUtils;
12821291
SDL_bool supportsColorspace;
@@ -10978,21 +10987,25 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
1097810987
VkPhysicalDeviceProperties deviceProperties;
1097910988
Uint32 i;
1098010989

10990+
const Uint8 *devicePriority = renderer->preferLowPower ?
10991+
DEVICE_PRIORITY_LOWPOWER :
10992+
DEVICE_PRIORITY_HIGHPERFORMANCE;
10993+
1098110994
/* Get the device rank before doing any checks, in case one fails.
1098210995
* Note: If no dedicated device exists, one that supports our features
1098310996
* would be fine
1098410997
*/
1098510998
renderer->vkGetPhysicalDeviceProperties(
1098610999
physicalDevice,
1098711000
&deviceProperties);
10988-
if (*deviceRank < DEVICE_PRIORITY[deviceProperties.deviceType]) {
11001+
if (*deviceRank < devicePriority[deviceProperties.deviceType]) {
1098911002
/* This device outranks the best device we've found so far!
1099011003
* This includes a dedicated GPU that has less features than an
1099111004
* integrated GPU, because this is a freak case that is almost
1099211005
* never intentionally desired by the end user
1099311006
*/
10994-
*deviceRank = DEVICE_PRIORITY[deviceProperties.deviceType];
10995-
} else if (*deviceRank > DEVICE_PRIORITY[deviceProperties.deviceType]) {
11007+
*deviceRank = devicePriority[deviceProperties.deviceType];
11008+
} else if (*deviceRank > devicePriority[deviceProperties.deviceType]) {
1099611009
/* Device is outranked by a previous device, don't even try to
1099711010
* run a query and reset the rank to avoid overwrites
1099811011
*/
@@ -11457,7 +11470,7 @@ static SDL_bool VULKAN_PrepareDriver(SDL_VideoDevice *_this)
1145711470
return result;
1145811471
}
1145911472

11460-
static SDL_GpuDevice *VULKAN_CreateDevice(SDL_bool debugMode)
11473+
static SDL_GpuDevice *VULKAN_CreateDevice(SDL_bool debugMode, SDL_bool preferLowPower)
1146111474
{
1146211475
VulkanRenderer *renderer;
1146311476

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

1148311497
if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) {
1148411498
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize Vulkan!");

test/testgpu_spinning_cube.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ init_render_state(void)
424424
SDL_GpuShader *fragment_shader;
425425
int i;
426426

427-
gpu_device = SDL_GpuCreateDevice(SDL_GPU_BACKEND_ALL, 1);
427+
gpu_device = SDL_GpuCreateDevice(SDL_GPU_BACKEND_ALL, 1, 0);
428428
CHECK_CREATE(gpu_device, "GPU device");
429429

430430
/* Claim the windows */

0 commit comments

Comments
 (0)