gcsx_opengl.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /* GCSx
  2. ** OPENGL.CPP
  3. **
  4. ** Core OpenGL functions
  5. */
  6. /*****************************************************************************
  7. ** Copyright (C) 2003-2006 Janson
  8. **
  9. ** This program is free software; you can redistribute it and/or modify
  10. ** it under the terms of the GNU General Public License as published by
  11. ** the Free Software Foundation; either version 2 of the License, or
  12. ** (at your option) any later version.
  13. **
  14. ** This program is distributed in the hope that it will be useful,
  15. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ** GNU General Public License for more details.
  18. **
  19. ** You should have received a copy of the GNU General Public License
  20. ** along with this program; if not, write to the Free Software
  21. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  22. *****************************************************************************/
  23. #include "all.h"
  24. int alphaOn = 0;
  25. int blendOn = 0;
  26. void oglInit(int width, int height) { start_func
  27. oglError("oglInit: selectVideoMode");
  28. oglDebug(glViewport(0, 0, width, height));
  29. oglDebug(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
  30. oglDebug(glEnable(GL_TEXTURE_2D));
  31. oglDebug(glDisable(GL_DEPTH_TEST));
  32. oglDebug(glAlphaFunc(GL_GREATER, 0));
  33. oglDebug(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
  34. oglDebug(glDisable(GL_ALPHA_TEST));
  35. oglDebug(glDisable(GL_BLEND));
  36. alphaOn = 0;
  37. blendOn = 0;
  38. // May change later
  39. oglDebug(glShadeModel(GL_SMOOTH));
  40. // Change to modulate to allow coloring
  41. oglDebug(glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE));
  42. oglDebug(glMatrixMode(GL_PROJECTION));
  43. oglDebug(glLoadIdentity());
  44. oglDebug(glOrtho(0, width, height, 0, 0, 1));
  45. oglDebug(glMatrixMode(GL_MODELVIEW));
  46. oglError("oglInit");
  47. // Some places optimize output and need to reset when GL is initialized
  48. TextureMap::setupOptimizations();
  49. }
  50. void oglAlphaMode(int transparency, int fullAlpha) { start_func
  51. if (fullAlpha) {
  52. if (!blendOn) {
  53. oglDebug(glEnable(GL_BLEND));
  54. blendOn = 1;
  55. }
  56. }
  57. else {
  58. if (blendOn) {
  59. oglDebug(glDisable(GL_BLEND));
  60. blendOn = 0;
  61. }
  62. }
  63. if ((transparency) && (!fullAlpha)) {
  64. if (!alphaOn) {
  65. oglDebug(glEnable(GL_ALPHA_TEST));
  66. alphaOn = 1;
  67. }
  68. }
  69. else {
  70. if (alphaOn) {
  71. oglDebug(glDisable(GL_ALPHA_TEST));
  72. alphaOn = 0;
  73. }
  74. }
  75. }
  76. int oglTestPossibleTextures(int width, int height, int withAlpha, int limit) { start_func
  77. // Test data-
  78. Uint8* testdata = new Uint8[width * height * (withAlpha ? 4 : 3)];
  79. Uint8* writeTo = testdata;
  80. for (int pos = width * height * (withAlpha ? 4 : 3); pos > 0; --pos)
  81. *writeTo++ = rand();
  82. // Limit to 8 seconds
  83. long long ticks = SDL_GetTicks();
  84. int time;
  85. // Add texture storage in powers of 2
  86. int allocSize = 64;
  87. GLuint* textures = new GLuint[allocSize];
  88. GLboolean* residencies = new GLboolean[allocSize];
  89. // Add textures 8 at a time
  90. int pos = 0;
  91. int found = 0;
  92. GLint getData;
  93. while (pos <= limit) {
  94. // Allocate more space?
  95. if (pos >= allocSize) {
  96. GLuint* newTextures = new GLuint[allocSize * 2];
  97. GLboolean* newResidencies = new GLboolean[allocSize * 2];
  98. memcpy(newTextures, textures, sizeof(GLuint[allocSize]));
  99. memcpy(newResidencies, residencies, sizeof(GLboolean[allocSize]));
  100. delete[] textures;
  101. delete[] residencies;
  102. textures = newTextures;
  103. residencies = newResidencies;
  104. allocSize *= 2;
  105. }
  106. // Create new texture
  107. oglDebug(glGenTextures(8, textures + pos));
  108. for (int subpos = 0; subpos < 8; ++subpos) {
  109. oglDebug(glBindTexture(GL_TEXTURE_2D, textures[pos]));
  110. oglDebug(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
  111. oglDebug(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
  112. residencies[pos] = GL_TRUE;
  113. oglDebug(glTexImage2D(GL_TEXTURE_2D, 0, withAlpha ? GL_RGBA : GL_RGB, width, height, 0,
  114. withAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, testdata));
  115. // Verify storage
  116. oglDebug(glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &getData));
  117. if (getData != width) {
  118. found = 1;
  119. break;
  120. }
  121. // Draw with texture
  122. glBegin(GL_QUADS);
  123. glTexCoord2f(0.0, 0.0); glVertex3i(0, 0, 0);
  124. glTexCoord2f(1.0, 0.0); glVertex3i(width, 0, 0);
  125. glTexCoord2f(1.0, 1.0); glVertex3i(width, height, 0);
  126. glTexCoord2f(0.0, 1.0); glVertex3i(0, height, 0);
  127. oglDebug(glEnd());
  128. ++pos;
  129. }
  130. if (found) break;
  131. // Verify residency of ALL textures
  132. if (glAreTexturesResident(pos, textures, residencies) == GL_FALSE) {
  133. found = 1;
  134. break;
  135. }
  136. if (SDL_GetTicks() - ticks > 8000) {
  137. time = 1;
  138. break;
  139. }
  140. }
  141. oglDebug(glDeleteTextures(pos, textures));
  142. delete[] textures;
  143. delete[] residencies;
  144. delete[] testdata;
  145. oglError("oglTestPossibleTextures");
  146. if (found) {
  147. if (withAlpha) {
  148. debugWrite("Maximum %dx%d RGBA textures resident: %d", width, height, pos - 8);
  149. }
  150. else {
  151. debugWrite("Maximum %dx%d RGB textures resident: %d", width, height, pos - 8);
  152. }
  153. return pos - 1;
  154. }
  155. else {
  156. if (withAlpha) {
  157. debugWrite("Maximum %dx%d RGBA textures resident: over %d", width, height, pos - 8);
  158. }
  159. else {
  160. debugWrite("Maximum %dx%d RGB textures resident: over %d", width, height, pos - 8);
  161. }
  162. if (time) {
  163. debugWrite("(test aborted due to time)");
  164. }
  165. return -1;
  166. }
  167. }
  168. void oglTestCapabilities() { start_func
  169. GLint result;
  170. // Reported capabilities
  171. oglDebug(glGetIntegerv(GL_DOUBLEBUFFER, &result));
  172. if (result == GL_TRUE) {
  173. debugWrite(DEBUG_VIDEO, "Double-buffering: Supported");
  174. }
  175. else {
  176. debugWrite(DEBUG_VIDEO, "Double-buffering: Not supported");
  177. }
  178. oglDebug(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &result));
  179. debugWrite(DEBUG_VIDEO, "Stated max texture size: %d", result);
  180. int maxSize = result;
  181. int minSize = 1;
  182. // Report on min/max sizes
  183. int size;
  184. for (int withAlpha = 0; withAlpha <= 1; ++withAlpha) {
  185. int found = 0;
  186. for (size = 64; size >= 1; size /= 2) {
  187. oglDebug(glTexImage2D(GL_PROXY_TEXTURE_2D, 0, withAlpha ? GL_RGBA : GL_RGB, size, size, 0,
  188. withAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, NULL));
  189. // Verify storage
  190. oglDebug(glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &result));
  191. if (result != size) {
  192. found = 1;
  193. break;
  194. }
  195. oglDebug(glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &result));
  196. if (result != size) {
  197. found = 1;
  198. break;
  199. }
  200. }
  201. if (found) size *= 2;
  202. else size = 1;
  203. if (withAlpha) {
  204. debugWrite(DEBUG_VIDEO, "Min texture size with alpha: %d", size);
  205. }
  206. else {
  207. debugWrite(DEBUG_VIDEO, "Min texture size, no alpha: %d", size);
  208. }
  209. if (size > minSize) minSize = size;
  210. found = 0;
  211. for (size = 64; size <= 65536; size *= 2) {
  212. oglDebug(glTexImage2D(GL_PROXY_TEXTURE_2D, 0, withAlpha ? GL_RGBA : GL_RGB, size, size, 0,
  213. withAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, NULL));
  214. // Verify storage
  215. oglDebug(glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &result));
  216. if (result != size) {
  217. found = 1;
  218. break;
  219. }
  220. oglDebug(glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &result));
  221. if (result != size) {
  222. found = 1;
  223. break;
  224. }
  225. }
  226. if (found) {
  227. size /= 2;
  228. if (withAlpha) {
  229. debugWrite(DEBUG_VIDEO, "Max texture size with alpha: %d", size);
  230. }
  231. else {
  232. debugWrite(DEBUG_VIDEO, "Max texture size, no alpha: %d", size);
  233. }
  234. }
  235. else {
  236. if (withAlpha) {
  237. debugWrite(DEBUG_VIDEO, "Max texture size with alpha: over 65536");
  238. }
  239. else {
  240. debugWrite(DEBUG_VIDEO, "Max texture size, no alpha: over 65536");
  241. }
  242. }
  243. // Track min between the three
  244. if (size < maxSize) maxSize = size;
  245. }
  246. // Attempt non-square texture
  247. oglDebug(glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, maxSize,
  248. maxSize / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
  249. // Clear error status (an error is expected here)
  250. while (glGetError()) ;
  251. // Verify storage
  252. oglDebug(glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &result));
  253. if (result == maxSize) {
  254. oglDebug(glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &result));
  255. if (result == maxSize / 2) {
  256. debugWrite(DEBUG_VIDEO, "Non-square textures: Supported");
  257. }
  258. else {
  259. debugWrite(DEBUG_VIDEO, "Non-square textures: Not supported");
  260. }
  261. }
  262. else {
  263. debugWrite(DEBUG_VIDEO, "Non-square textures: Not supported");
  264. }
  265. // Attempt non-^2 texture
  266. glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, 100, 100, 0,
  267. GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  268. // Clear error status (an error is expected here)
  269. while (glGetError()) ;
  270. // Verify storage
  271. oglDebug(glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &result));
  272. oglError("oglTestCapabilities");
  273. if (result == 100) {
  274. debugWrite(DEBUG_VIDEO, "Non-^2 textures: Supported");
  275. }
  276. else {
  277. debugWrite(DEBUG_VIDEO, "Non-^2 textures: Not supported");
  278. }
  279. // Always force ^2 textures as some cards support non-^2 textures but VERY SLOWLY
  280. config->write(OGL_POWER_OF_TWO, 1);
  281. config->write(OGL_MIN_SIZE, minSize);
  282. config->write(OGL_MAX_SIZE, maxSize);
  283. }
  284. void oglError(const char* note) { start_func
  285. const char* errStr;
  286. while (GLenum err = glGetError()) {
  287. switch (err) {
  288. case GL_INVALID_ENUM:
  289. errStr = "Invalid Enum";
  290. break;
  291. case GL_INVALID_VALUE:
  292. errStr = "Invalid Value";
  293. break;
  294. case GL_INVALID_OPERATION:
  295. errStr = "Invalid Operation";
  296. break;
  297. case GL_STACK_OVERFLOW:
  298. errStr = "Stack Overflow";
  299. break;
  300. case GL_STACK_UNDERFLOW:
  301. errStr = "Stack Underflow";
  302. break;
  303. case GL_OUT_OF_MEMORY:
  304. errStr = "Out of Memory";
  305. break;
  306. }
  307. debugWrite(DEBUG_VIDEO, "%s: GL Error: %s", note, errStr);
  308. }
  309. }