SDL: Added a utility function to calculate the next power of 2 for a value

From b299cb3d3c2bed0a9d14db8f12ff6515a16ef5aa Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 17 Jul 2022 08:31:16 -0700
Subject: [PATCH] Added a utility function to calculate the next power of 2 for
 a value

---
 Makefile.os2                          |  2 +-
 Makefile.w32                          |  2 +-
 VisualC-GDK/SDL/SDL.vcxproj           |  3 +-
 VisualC-GDK/SDL/SDL.vcxproj.filters   |  3 +-
 VisualC-WinRT/SDL-UWP.vcxproj         |  1 +
 VisualC-WinRT/SDL-UWP.vcxproj.filters |  5 ++-
 VisualC/SDL/SDL.vcxproj               |  3 +-
 VisualC/SDL/SDL.vcxproj.filters       |  3 +-
 src/SDL_utils.c                       | 50 +++++++++++++++++++++++++++
 src/SDL_utils_c.h                     | 32 +++++++++++++++++
 src/audio/SDL_audio.c                 |  9 ++---
 src/render/opengl/SDL_render_gl.c     | 16 ++-------
 src/render/opengles/SDL_render_gles.c | 16 ++-------
 13 files changed, 105 insertions(+), 40 deletions(-)
 create mode 100644 src/SDL_utils.c
 create mode 100644 src/SDL_utils_c.h

diff --git a/Makefile.os2 b/Makefile.os2
index 2f8d5ff3467..f68755fec24 100644
--- a/Makefile.os2
+++ b/Makefile.os2
@@ -67,7 +67,7 @@ CFLAGS_DLL+= -DSDL_BUILD_MAJOR_VERSION=$(MAJOR_VERSION)
 CFLAGS_DLL+= -DSDL_BUILD_MINOR_VERSION=$(MINOR_VERSION)
 CFLAGS_DLL+= -DSDL_BUILD_MICRO_VERSION=$(MICRO_VERSION)
 
-SRCS = SDL.c SDL_assert.c SDL_error.c SDL_guid.c SDL_log.c SDL_dataqueue.c SDL_hints.c SDL_list.c
+SRCS = SDL.c SDL_assert.c SDL_error.c SDL_guid.c SDL_log.c SDL_dataqueue.c SDL_hints.c SDL_list.c SDL_utils.c
 SRCS+= SDL_getenv.c SDL_iconv.c SDL_malloc.c SDL_memcpy.c SDL_memset.c SDL_qsort.c SDL_stdlib.c SDL_string.c SDL_strtokr.c SDL_crc32.c
 SRCS+= SDL_cpuinfo.c SDL_atomic.c SDL_spinlock.c SDL_thread.c SDL_timer.c
 SRCS+= SDL_rwops.c SDL_power.c
diff --git a/Makefile.w32 b/Makefile.w32
index 978afab3311..feacca8984d 100644
--- a/Makefile.w32
+++ b/Makefile.w32
@@ -43,7 +43,7 @@ CFLAGS_DLL+= -DSDL_BUILD_MICRO_VERSION=$(MICRO_VERSION)
 
 RCFLAGS = -q -r -bt=nt $(INCPATH)
 
-SRCS = SDL.c SDL_assert.c SDL_error.c SDL_guid.c SDL_log.c SDL_dataqueue.c SDL_hints.c SDL_list.c
+SRCS = SDL.c SDL_assert.c SDL_error.c SDL_guid.c SDL_log.c SDL_dataqueue.c SDL_hints.c SDL_list.c SDL_utils.c
 SRCS+= SDL_getenv.c SDL_iconv.c SDL_malloc.c SDL_memcpy.c SDL_memset.c SDL_qsort.c SDL_stdlib.c SDL_string.c SDL_strtokr.c SDL_crc32.c
 SRCS+= SDL_cpuinfo.c SDL_atomic.c SDL_spinlock.c SDL_thread.c SDL_timer.c
 SRCS+= SDL_rwops.c SDL_power.c
diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj
index c511fda62b6..25478f392b4 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj
+++ b/VisualC-GDK/SDL/SDL.vcxproj
@@ -689,6 +689,7 @@
     <ClCompile Include="..\..\src\SDL_error.c" />
     <ClCompile Include="..\..\src\SDL_hints.c" />
     <ClCompile Include="..\..\src\SDL_log.c" />
+    <ClCompile Include="..\..\src\SDL_utils.c" />
     <ClCompile Include="..\..\src\sensor\dummy\SDL_dummysensor.c" />
     <ClCompile Include="..\..\src\sensor\SDL_sensor.c" />
     <ClCompile Include="..\..\src\sensor\windows\SDL_windowssensor.c" />
@@ -756,4 +757,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters
index 59a3d727106..dfbce651a9e 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj.filters
+++ b/VisualC-GDK/SDL/SDL.vcxproj.filters
@@ -852,6 +852,7 @@
     <ClCompile Include="..\..\src\SDL_guid.c" />
     <ClCompile Include="..\..\src\SDL_hints.c" />
     <ClCompile Include="..\..\src\SDL_list.c" />
+    <ClCompile Include="..\..\src\SDL_utils.c" />
     <ClCompile Include="..\..\src\audio\SDL_audio.c">
       <Filter>audio</Filter>
     </ClCompile>
@@ -1373,4 +1374,4 @@
   <ItemGroup>
     <ResourceCompile Include="..\..\src\main\windows\version.rc" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/VisualC-WinRT/SDL-UWP.vcxproj b/VisualC-WinRT/SDL-UWP.vcxproj
index aeaea7f43ec..9ae69309556 100644
--- a/VisualC-WinRT/SDL-UWP.vcxproj
+++ b/VisualC-WinRT/SDL-UWP.vcxproj
@@ -304,6 +304,7 @@
     <ClCompile Include="..\src\SDL_guid.c" />
     <ClCompile Include="..\src\SDL_hints.c" />
     <ClCompile Include="..\src\SDL_log.c" />
+    <ClCompile Include="..\src\SDL_utils.c" />
     <ClCompile Include="..\src\sensor\dummy\SDL_dummysensor.c" />
     <ClCompile Include="..\src\sensor\SDL_sensor.c" />
     <ClCompile Include="..\src\stdlib\SDL_crc32.c" />
diff --git a/VisualC-WinRT/SDL-UWP.vcxproj.filters b/VisualC-WinRT/SDL-UWP.vcxproj.filters
index 98b117d424d..879c07c05d7 100644
--- a/VisualC-WinRT/SDL-UWP.vcxproj.filters
+++ b/VisualC-WinRT/SDL-UWP.vcxproj.filters
@@ -792,6 +792,9 @@
     <ClCompile Include="..\src\SDL_list.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\SDL_utils.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="..\src\haptic\windows\SDL_dinputhaptic.c">
       <Filter>Source Files</Filter>
     </ClCompile>
@@ -837,4 +840,4 @@
       <Filter>Source Files</Filter>
     </ClCompile>
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj
index cb386bcf0be..07e5042fcd8 100644
--- a/VisualC/SDL/SDL.vcxproj
+++ b/VisualC/SDL/SDL.vcxproj
@@ -557,6 +557,7 @@
     <ClCompile Include="..\..\src\SDL_error.c" />
     <ClCompile Include="..\..\src\SDL_hints.c" />
     <ClCompile Include="..\..\src\SDL_log.c" />
+    <ClCompile Include="..\..\src\SDL_utils.c" />
     <ClCompile Include="..\..\src\sensor\dummy\SDL_dummysensor.c" />
     <ClCompile Include="..\..\src\sensor\SDL_sensor.c" />
     <ClCompile Include="..\..\src\sensor\windows\SDL_windowssensor.c" />
@@ -624,4 +625,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters
index c6efccb591b..fc5318a0958 100644
--- a/VisualC/SDL/SDL.vcxproj.filters
+++ b/VisualC/SDL/SDL.vcxproj.filters
@@ -845,6 +845,7 @@
     <ClCompile Include="..\..\src\SDL_guid.c" />
     <ClCompile Include="..\..\src\SDL_hints.c" />
     <ClCompile Include="..\..\src\SDL_list.c" />
+    <ClCompile Include="..\..\src\SDL_utils.c" />
     <ClCompile Include="..\..\src\audio\SDL_audio.c">
       <Filter>audio</Filter>
     </ClCompile>
@@ -1348,4 +1349,4 @@
   <ItemGroup>
     <ResourceCompile Include="..\..\src\main\windows\version.rc" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/SDL_utils.c b/src/SDL_utils.c
new file mode 100644
index 00000000000..e375d7443c7
--- /dev/null
+++ b/src/SDL_utils.c
@@ -0,0 +1,50 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+#include "SDL_utils_c.h"
+
+/* Common utility functions that aren't in the public API */
+
+int SDL_powerof2(int x)
+{
+    int value;
+
+    /* We could use this trick for 32-bit values:
+     * value = x;
+     * value -= 1;
+     * value |= value >> 1;
+     * value |= value >> 2;
+     * value |= value >> 4;
+     * value |= value >> 8;
+     * value |= value >> 16;
+     * value += 1;
+     *
+     * ... but this is more readable:
+     */
+    value = 1;
+    while (value < x) {
+        value <<= 1;
+    }
+    return value;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h
new file mode 100644
index 00000000000..8f405159fb8
--- /dev/null
+++ b/src/SDL_utils_c.h
@@ -0,0 +1,32 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_utils_h_
+#define SDL_utils_h_
+
+/* Common utility functions that aren't in the public API */
+
+/* Return the smallest power of 2 greater than or equal to 2 */
+int SDL_powerof2(int x);
+
+#endif /* SDL_utils_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index b9c38dc13f0..9c47d40ba01 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -27,6 +27,7 @@
 #include "SDL_audio_c.h"
 #include "SDL_sysaudio.h"
 #include "../thread/SDL_systhread.h"
+#include "../SDL_utils_c.h"
 
 #define _THIS SDL_AudioDevice *_this
 
@@ -1417,13 +1418,7 @@ open_audio_device(const char *devname, int iscapture,
      * value we got from 'desired' and round up to the nearest value
      */
     if (!current_audio.impl.SupportsNonPow2Samples && device->spec.samples > 0) {
-        device->spec.samples -= 1;
-        device->spec.samples |= device->spec.samples >> 1;
-        device->spec.samples |= device->spec.samples >> 2;
-        device->spec.samples |= device->spec.samples >> 4;
-        device->spec.samples |= device->spec.samples >> 8;
-        device->spec.samples |= device->spec.samples >> 16;
-        device->spec.samples += 1;
+        device->spec.samples = SDL_powerof2(device->spec.samples);
     }
 
     if (current_audio.impl.OpenDevice(device, devname) < 0) {
diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c
index 73a5694ddeb..202e17d1a7b 100644
--- a/src/render/opengl/SDL_render_gl.c
+++ b/src/render/opengl/SDL_render_gl.c
@@ -25,6 +25,7 @@
 #include "SDL_opengl.h"
 #include "../SDL_sysrender.h"
 #include "SDL_shaders_gl.h"
+#include "../../SDL_utils_c.h"
 
 #ifdef __MACOSX__
 #include <OpenGL/OpenGL.h>
@@ -411,17 +412,6 @@ GL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
     return SDL_TRUE;
 }
 
-SDL_FORCE_INLINE int
-power_of_2(int input)
-{
-    int value = 1;
-
-    while (value < input) {
-        value <<= 1;
-    }
-    return value;
-}
-
 SDL_FORCE_INLINE SDL_bool
 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
                GLint* internalFormat, GLenum* format, GLenum* type)
@@ -540,8 +530,8 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
         data->texw = (GLfloat) texture_w;
         data->texh = (GLfloat) texture_h;
     } else {
-        texture_w = power_of_2(texture->w);
-        texture_h = power_of_2(texture->h);
+        texture_w = SDL_powerof2(texture->w);
+        texture_h = SDL_powerof2(texture->h);
         data->texw = (GLfloat) (texture->w) / texture_w;
         data->texh = (GLfloat) texture->h / texture_h;
     }
diff --git a/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c
index 9afd8d1af76..588644980dd 100644
--- a/src/render/opengles/SDL_render_gles.c
+++ b/src/render/opengles/SDL_render_gles.c
@@ -25,6 +25,7 @@
 #include "SDL_hints.h"
 #include "SDL_opengles.h"
 #include "../SDL_sysrender.h"
+#include "../../SDL_utils_c.h"
 
 /* To prevent unnecessary window recreation,
  * these should match the defaults selected in SDL_GL_ResetAttributes
@@ -303,17 +304,6 @@ GLES_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
     return SDL_TRUE;
 }
 
-static SDL_INLINE int
-power_of_2(int input)
-{
-    int value = 1;
-
-    while (value < input) {
-        value <<= 1;
-    }
-    return value;
-}
-
 static int
 GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 {
@@ -374,8 +364,8 @@ GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 
     data->type = GL_TEXTURE_2D;
     /* no NPOV textures allowed in OpenGL ES (yet) */
-    texture_w = power_of_2(texture->w);
-    texture_h = power_of_2(texture->h);
+    texture_w = SDL_powerof2(texture->w);
+    texture_h = SDL_powerof2(texture->h);
     data->texw = (GLfloat) texture->w / texture_w;
     data->texh = (GLfloat) texture->h / texture_h;