/* ============= Q_strreplace replaces content of find by replace in dest ============= */ qboolean Q_strreplace(char *dest, int destsize, const char *find, const char *replace) { int lend; char *s; char backup[32000]; // big, but small enough to fit in PPC stack lend = strlen(dest); if (lend >= destsize) { Ren_Fatal("Q_strreplace: already overflowed"); } s = strstr(dest, find); if (!s) { return qfalse; } else { int lstart, lfind, lreplace; Q_strncpyz(backup, dest, lend + 1); lstart = s - dest; lfind = strlen(find); lreplace = strlen(replace); strncpy(s, replace, destsize - lstart - 1); strncpy(s + lreplace, backup + lstart + lfind, destsize - lstart - lreplace - 1); return qtrue; } }
void R_CopyToFBO(FBO_t *from, FBO_t *to, GLuint mask, GLuint filter) { if (glConfig2.framebufferBlitAvailable) { vec2_t size; if (from) { glBindFramebuffer(GL_READ_FRAMEBUFFER, from->frameBuffer); size[0] = from->width; size[1] = from->height; } else { glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); size[0] = glConfig.vidWidth; size[1] = glConfig.vidHeight; } glBindFramebuffer(GL_DRAW_FRAMEBUFFER, to->frameBuffer); glBlitFramebuffer(0, 0, size[0], size[1], 0, 0, to->width, to->height, mask, filter); //Just set the read buffer to the target as well otherwise we might get f****d.. glBindFramebuffer(GL_FRAMEBUFFER, to->frameBuffer); glState.currentFBO = to; } else { // FIXME add non EXT_framebuffer_blit code Ren_Fatal("R_CopyToFBO no framebufferblitting available"); } }
int RE_InitOpenGlSubsystems(void) { #ifndef FEATURE_RENDERER_GLES GLenum glewResult; #endif #if !defined(FEATURE_RENDERER_GLES) #if defined(FEATURE_RENDERER2) glewExperimental = GL_TRUE; #endif glewResult = glewInit(); if (GLEW_OK != glewResult) { // glewInit failed, something is seriously wrong Ren_Fatal("GLW_StartOpenGL() - could not load OpenGL subsystem: %s", glewGetErrorString(glewResult)); } else { Com_Printf("Using GLEW %s\n", glewGetString(GLEW_VERSION)); } #endif if (!GLimp_InitOpenGLContext()) { return qfalse; } return qtrue; }
static boolean empty_output_buffer(j_compress_ptr cinfo) { my_dest_ptr dest = ( my_dest_ptr ) cinfo->dest; jpeg_destroy_compress(cinfo); // Make crash fatal or we would probably leak memory. Ren_Fatal("Output buffer for encoded JPEG image has insufficient size of %d bytes", dest->size); return FALSE; }
static void R_CheckDefaultBuffer() { glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0); glState.currentFBO = NULL; { unsigned int fbostatus = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (fbostatus != GL_FRAMEBUFFER_COMPLETE) { if (fbostatus == GL_FRAMEBUFFER_UNDEFINED) { Ren_Fatal("Default framebuffer is undefined!"); } else { Ren_Fatal("There is an issue with the opengl context:s default framebuffer...%i", fbostatus); } } } }
/* ============ R_CreateIBO ============ */ IBO_t *R_CreateIBO(const char *name, byte *indexes, int indexesSize, vboUsage_t usage) { IBO_t *ibo; int glUsage; switch (usage) { case VBO_USAGE_STATIC: glUsage = GL_STATIC_DRAW; break; case VBO_USAGE_DYNAMIC: glUsage = GL_DYNAMIC_DRAW; break; default: glUsage = 0; Ren_Fatal("bad vboUsage_t given: %i", usage); break; } if (strlen(name) >= MAX_QPATH) { Ren_Drop("R_CreateIBO: \"%s\" is too long\n", name); } // make sure the render thread is stopped R_IssuePendingRenderCommands(); ibo = (IBO_t *)ri.Hunk_Alloc(sizeof(*ibo), h_low); Com_AddToGrowList(&tr.ibos, ibo); Q_strncpyz(ibo->name, name, sizeof(ibo->name)); ibo->indexesSize = indexesSize; glGenBuffers(1, &ibo->indexesVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->indexesVBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexesSize, indexes, glUsage); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL_CheckErrors(); return ibo; }
static void R_InitUnitCubeVBO() { vec3_t mins = { -1, -1, -1 }; vec3_t maxs = { 1, 1, 1 }; int i; srfVert_t *verts; srfTriangle_t *triangles; if (glConfig.smpActive) { Ren_Fatal("R_InitUnitCubeVBO: FIXME SMP"); } tess.multiDrawPrimitives = 0; tess.numIndexes = 0; tess.numVertexes = 0; Tess_AddCube(vec3_origin, mins, maxs, colorWhite); verts = (srfVert_t *)ri.Hunk_AllocateTempMemory(tess.numVertexes * sizeof(srfVert_t)); triangles = (srfTriangle_t *)ri.Hunk_AllocateTempMemory((tess.numIndexes / 3) * sizeof(srfTriangle_t)); for (i = 0; i < tess.numVertexes; i++) { VectorCopy(tess.xyz[i], verts[i].xyz); } for (i = 0; i < (tess.numIndexes / 3); i++) { triangles[i].indexes[0] = tess.indexes[i * 3 + 0]; triangles[i].indexes[1] = tess.indexes[i * 3 + 1]; triangles[i].indexes[2] = tess.indexes[i * 3 + 2]; } tr.unitCubeVBO = R_CreateVBO2("unitCube_VBO", tess.numVertexes, verts, ATTR_POSITION, VBO_USAGE_STATIC); tr.unitCubeIBO = R_CreateIBO2("unitCube_IBO", tess.numIndexes / 3, triangles, VBO_USAGE_STATIC); ri.Hunk_FreeTempMemory(triangles); ri.Hunk_FreeTempMemory(verts); tess.multiDrawPrimitives = 0; tess.numIndexes = 0; tess.numVertexes = 0; }
int Com_AddToGrowList(growList_t *list, void *data) { void **old; if (list->currentElements != list->maxElements) { list->elements[list->currentElements] = data; return list->currentElements++; } // grow, reallocate and move old = list->elements; if (list->maxElements < 0) { Ren_Fatal("Com_AddToGrowList: maxElements = %i", list->maxElements); } if (list->maxElements == 0) { // initialize the list to hold 100 elements Com_InitGrowList(list, 100); return Com_AddToGrowList(list, data); } list->maxElements *= 2; //Com_DPrintf("Resizing growlist to %i maxElements\n", list->maxElements); list->elements = (void **)Com_Allocate(list->maxElements * sizeof(void *)); if (!list->elements) { Ren_Drop("Growlist alloc failed"); } Com_Memcpy(list->elements, old, list->currentElements * sizeof(void *)); Com_Dealloc(old); return Com_AddToGrowList(list, data); }
/** * @brief Make sure there is enough command space, waiting on the * render thread if needed. * @param[in] bytes * @return */ void *R_GetCommandBuffer(unsigned int bytes) { renderCommandList_t *cmdList = &backEndData->commands; // always leave room for the swap buffers and end of list commands // - added swapBuffers_t from ET if (cmdList->used + bytes + (sizeof(swapBuffersCommand_t) + sizeof(int)) > MAX_RENDER_COMMANDS) { if (bytes > MAX_RENDER_COMMANDS - (sizeof(swapBuffersCommand_t) + sizeof(int))) { Ren_Fatal("R_GetCommandBuffer: bad size %u", bytes); } // if we run out of room, just start dropping commands return NULL; } cmdList->used += bytes; return cmdList->cmds + cmdList->used - bytes; }
static qboolean GLimp_CheckForVersionExtension(const char *ext, int coresince, qboolean required, cvar_t *var) { qboolean result = qfalse; if ((coresince >= 0 && coresince <= glConfig2.contextCombined) || GL_CheckForExtension(ext)) { if (var && var->integer) { result = qtrue; } else if (!var) { result = qtrue; } } if (required && !result) { Ren_Fatal(MSG_ERR_OLD_VIDEO_DRIVER "\nYour GL driver is missing support for: %s\n", ext); } if (result) { Com_Printf("...found OpenGL extension - %s\n", ext); } else { if (var) { Com_Printf("...ignoring %s\n", ext); } else { Com_Printf("...%s not found\n", ext); } } return result; }
int MemStreamRead(memStream_t *s, void *buffer, int len) { int ret = 1; if (s == NULL || buffer == NULL) { return 0; } if (s->curPos + len > s->buffer + s->bufSize) { s->flags |= MEMSTREAM_FLAGS_EOF; len = s->buffer + s->bufSize - s->curPos; ret = 0; Ren_Fatal("MemStreamRead: EOF reached"); } Com_Memcpy(buffer, s->curPos, len); s->curPos += len; return ret; }
static void GLimp_DetectAvailableModes(void) { int i, j; char buf[MAX_STRING_CHARS] = { 0 }; SDL_Rect modes[128]; int numModes = 0; int display = 0; SDL_DisplayMode windowMode; if (!main_window) { if (!SDL_GetNumVideoDisplays()) { Ren_Fatal("There is no available display to open a game screen - %s", SDL_GetError()); return; } // Use the zero display index display = 0; } else { // Detect the used display display = SDL_GetWindowDisplayIndex(main_window); } // was SDL_GetWindowDisplayMode if (SDL_GetDesktopDisplayMode(display, &windowMode) < 0) { Ren_Warning("Couldn't get desktop display mode, no resolutions detected - %s\n", SDL_GetError()); return; } for (i = 0; i < SDL_GetNumDisplayModes(display); i++) { SDL_DisplayMode mode; if (SDL_GetDisplayMode(display, i, &mode) < 0) { continue; } if (!mode.w || !mode.h) { Ren_Print("Display supports any resolution\n"); return; } if (windowMode.format != mode.format) { continue; } // SDL can give the same resolution with different refresh rates. // Only list resolution once. for (j = 0; j < numModes; j++) { if (mode.w == modes[j].w && mode.h == modes[j].h) { break; } } if (j != numModes) { continue; } modes[numModes].w = mode.w; modes[numModes].h = mode.h; numModes++; } if (numModes > 1) { qsort(modes, numModes, sizeof(SDL_Rect), GLimp_CompareModes); } for (i = 0; i < numModes; i++) { const char *newModeString = va("%ux%u ", modes[i].w, modes[i].h); if (strlen(newModeString) < (int)sizeof(buf) - strlen(buf)) { Q_strcat(buf, sizeof(buf), newModeString); } else { Ren_Warning("Skipping mode %ux%u, buffer too small\n", modes[i].w, modes[i].h); } } if (*buf) { buf[strlen(buf) - 1] = 0; Ren_Print("Available modes [%i]: '%s'\n", numModes, buf); ri.Cvar_Set("r_availableModes", buf); } }
static void R_BuildGammaProgram(void) { GLint compiled; gammaProgram.vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); gammaProgram.fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); glShaderSourceARB(gammaProgram.vertexShader, 1, (const GLcharARB **)&simpleGammaVert, NULL); glShaderSourceARB(gammaProgram.fragmentShader, 1, (const GLcharARB **)&simpleGammaFrag, NULL); glCompileShaderARB(gammaProgram.vertexShader); glCompileShaderARB(gammaProgram.fragmentShader); glGetObjectParameterivARB(gammaProgram.vertexShader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint blen = 0; GLsizei slen = 0; glGetShaderiv(gammaProgram.vertexShader, GL_INFO_LOG_LENGTH, &blen); if (blen > 1) { GLchar *compiler_log; compiler_log = (GLchar *) malloc(blen); glGetInfoLogARB(gammaProgram.vertexShader, blen, &slen, compiler_log); Ren_Fatal("Failed to compile the gamma vertex shader reason: %s\n", compiler_log); } else { Ren_Fatal("Failed to compile the gamma vertex shader\n"); } } glGetObjectParameterivARB(gammaProgram.fragmentShader, GL_COMPILE_STATUS, &compiled); if (!compiled) { Ren_Fatal("Failed to compile the gamma fragment shader\n"); } gammaProgram.program = glCreateProgramObjectARB(); if (!gammaProgram.program) { Ren_Fatal("Failed to create program\n"); } glAttachObjectARB(gammaProgram.program, gammaProgram.vertexShader); glAttachObjectARB(gammaProgram.program, gammaProgram.fragmentShader); glLinkProgramARB(gammaProgram.program); glGetProgramivARB(gammaProgram.program, GL_LINK_STATUS, &compiled); // this throws glGetError() = 0x500 if (!compiled) { Ren_Fatal("Failed to link gamma shaders\n"); } glUseProgramObjectARB(gammaProgram.program); gammaProgram.currentMapUniform = glGetUniformLocation(gammaProgram.program, "u_CurrentMap"); gammaProgram.gammaUniform = glGetUniformLocation(gammaProgram.program, "u_gamma"); glUseProgramObjectARB(0); }
/* ============ R_CreateIBO2 ============ */ IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t *triangles, vboUsage_t usage) { IBO_t *ibo; int i, j; byte *indexes; int indexesSize; int indexesOfs; srfTriangle_t *tri; glIndex_t index; int glUsage; switch (usage) { case VBO_USAGE_STATIC: glUsage = GL_STATIC_DRAW; break; case VBO_USAGE_DYNAMIC: glUsage = GL_DYNAMIC_DRAW; break; default: glUsage = 0; Ren_Fatal("bad vboUsage_t given: %i", usage); break; } if (!numTriangles) { return NULL; } if (strlen(name) >= MAX_QPATH) { Ren_Drop("R_CreateIBO2: \"%s\" is too long\n", name); } // make sure the render thread is stopped R_IssuePendingRenderCommands(); ibo = (IBO_t *)ri.Hunk_Alloc(sizeof(*ibo), h_low); Com_AddToGrowList(&tr.ibos, ibo); Q_strncpyz(ibo->name, name, sizeof(ibo->name)); indexesSize = numTriangles * 3 * sizeof(glIndex_t); indexes = (byte *)ri.Hunk_AllocateTempMemory(indexesSize); indexesOfs = 0; //Ren_Print("sizeof(glIndex_t) = %i\n", sizeof(glIndex_t)); for (i = 0, tri = triangles; i < numTriangles; i++, tri++) { for (j = 0; j < 3; j++) { index = tri->indexes[j]; memcpy(indexes + indexesOfs, &index, sizeof(glIndex_t)); indexesOfs += sizeof(glIndex_t); } } ibo->indexesSize = indexesSize; ibo->indexesNum = numTriangles * 3; glGenBuffers(1, &ibo->indexesVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo->indexesVBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexesSize, indexes, glUsage); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL_CheckErrors(); ri.Hunk_FreeTempMemory(indexes); return ibo; }
/* ============ R_CreateVBO ============ */ VBO_t *R_CreateVBO(const char *name, byte *vertexes, int vertexesSize, vboUsage_t usage) { VBO_t *vbo; int glUsage; switch (usage) { case VBO_USAGE_STATIC: glUsage = GL_STATIC_DRAW; break; case VBO_USAGE_DYNAMIC: glUsage = GL_DYNAMIC_DRAW; break; default: glUsage = 0; //Prevents warning Ren_Fatal("bad vboUsage_t given: %i", usage); break; } if (strlen(name) >= MAX_QPATH) { Ren_Drop("R_CreateVBO: \"%s\" is too long\n", name); } // make sure the render thread is stopped R_IssuePendingRenderCommands(); vbo = (VBO_t *)ri.Hunk_Alloc(sizeof(*vbo), h_low); Com_AddToGrowList(&tr.vbos, vbo); Q_strncpyz(vbo->name, name, sizeof(vbo->name)); vbo->ofsXYZ = 0; vbo->ofsTexCoords = 0; vbo->ofsLightCoords = 0; vbo->ofsBinormals = 0; vbo->ofsTangents = 0; vbo->ofsNormals = 0; vbo->ofsColors = 0; vbo->ofsPaintColors = 0; vbo->ofsLightDirections = 0; vbo->ofsBoneIndexes = 0; vbo->ofsBoneWeights = 0; vbo->sizeXYZ = 0; vbo->sizeTangents = 0; vbo->sizeBinormals = 0; vbo->sizeNormals = 0; vbo->vertexesSize = vertexesSize; glGenBuffers(1, &vbo->vertexesVBO); glBindBuffer(GL_ARRAY_BUFFER, vbo->vertexesVBO); glBufferData(GL_ARRAY_BUFFER, vertexesSize, vertexes, glUsage); glBindBuffer(GL_ARRAY_BUFFER, 0); GL_CheckErrors(); return vbo; }
static void GLimp_InitExtensionsR2(void) { Ren_Print("Initializing OpenGL extensions\n"); // GL_ARB_multitexture if (glConfig.driverType != GLDRV_OPENGL3) { if (GLEW_ARB_multitexture) { glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &glConfig.maxActiveTextures); if (glConfig.maxActiveTextures > 1) { Ren_Print("...found OpenGL extension - GL_ARB_multitexture\n"); } else { Ren_Fatal(MSG_ERR_OLD_VIDEO_DRIVER "\nYour GL driver is missing support for: GL_ARB_multitexture, < 2 texture units"); } } else { Ren_Fatal(MSG_ERR_OLD_VIDEO_DRIVER "\nYour GL driver is missing support for: GL_ARB_multitexture"); } } // GL_ARB_depth_texture GLimp_CheckForVersionExtension("GL_ARB_depth_texture", 130, qtrue, NULL); if (GLimp_CheckForVersionExtension("GL_ARB_texture_cube_map", 130, qtrue, NULL)) { glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig2.maxCubeMapTextureSize); } GL_CheckErrors(); GLimp_CheckForVersionExtension("GL_ARB_vertex_program", 210, qtrue, NULL); GLimp_CheckForVersionExtension("GL_ARB_vertex_buffer_object", 300, qtrue, NULL); // GL_ARB_occlusion_query glConfig2.occlusionQueryAvailable = qfalse; glConfig2.occlusionQueryBits = 0; if (GLimp_CheckForVersionExtension("GL_ARB_occlusion_query", 150, qfalse, r_ext_occlusion_query)) { glConfig2.occlusionQueryAvailable = qtrue; glGetQueryivARB(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &glConfig2.occlusionQueryBits); } GL_CheckErrors(); GLimp_CheckForVersionExtension("GL_ARB_shader_objects", 210, qtrue, NULL); if (GLimp_CheckForVersionExtension("GL_ARB_vertex_shader", 210, qtrue, NULL)) { int reservedComponents; GL_CheckErrors(); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig2.maxVertexUniforms); GL_CheckErrors(); //glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats); GL_CheckErrors(); glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig2.maxVertexAttribs); GL_CheckErrors(); reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices glConfig2.maxVertexSkinningBones = (int) Q_bound(0.0, (Q_max(glConfig2.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES); glConfig2.vboVertexSkinningAvailable = (qboolean)(r_vboVertexSkinning->integer && ((glConfig2.maxVertexSkinningBones >= 12) ? qtrue : qfalse)); } GL_CheckErrors(); GLimp_CheckForVersionExtension("GL_ARB_fragment_shader", 210, qtrue, NULL); // GL_ARB_shading_language_100 if (GLimp_CheckForVersionExtension("GL_ARB_shading_language_100", 210, qtrue, NULL)) { Q_strncpyz(glConfig2.shadingLanguageVersion, (char *)glGetString(GL_SHADING_LANGUAGE_VERSION_ARB), sizeof(glConfig2.shadingLanguageVersion)); sscanf(glConfig2.shadingLanguageVersion, "%d.%d", &glConfig2.glslMajorVersion, &glConfig2.glslMinorVersion); } GL_CheckErrors(); glConfig2.textureNPOTAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_ARB_texture_non_power_of_two", 300, qfalse, r_ext_texture_non_power_of_two)) { glConfig2.textureNPOTAvailable = qtrue; } glConfig2.drawBuffersAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_ARB_draw_buffers", /* -1 */ 300, qfalse, r_ext_draw_buffers)) { glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &glConfig2.maxDrawBuffers); glConfig2.drawBuffersAvailable = qtrue; } glConfig2.textureHalfFloatAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_ARB_half_float_pixel", 300, qfalse, r_ext_half_float_pixel)) { glConfig2.textureHalfFloatAvailable = qtrue; } glConfig2.textureFloatAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_ARB_texture_float", 300, qfalse, r_ext_texture_float)) { glConfig2.textureFloatAvailable = qtrue; } glConfig2.ARBTextureCompressionAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_ARB_texture_compression", 300, qfalse, r_ext_compressed_textures)) { glConfig2.ARBTextureCompressionAvailable = qtrue; glConfig.textureCompression = TC_NONE; } glConfig2.vertexArrayObjectAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_ARB_vertex_array_object", 300, qfalse, r_ext_vertex_array_object)) { glConfig2.vertexArrayObjectAvailable = qtrue; } // GL_EXT_texture_compression_s3tc if (GLimp_CheckForVersionExtension("GL_EXT_texture_compression_s3tc", -1, qfalse, r_ext_compressed_textures)) { glConfig.textureCompression = TC_S3TC; } glConfig2.texture3DAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_EXT_texture3D", 170, qfalse, NULL)) { glConfig2.texture3DAvailable = qtrue; } glConfig2.stencilWrapAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_EXT_stencil_wrap", 210, qfalse, r_ext_stencil_wrap)) { glConfig2.stencilWrapAvailable = qtrue; } glConfig2.textureAnisotropyAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_EXT_texture_filter_anisotropic", -1, qfalse, r_ext_texture_filter_anisotropic)) { glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig2.maxTextureAnisotropy); glConfig2.textureAnisotropyAvailable = qtrue; } GL_CheckErrors(); GLimp_CheckForVersionExtension("GL_EXT_stencil_two_side", 210, qfalse, r_ext_stencil_two_side); GLimp_CheckForVersionExtension("GL_EXT_depth_bounds_test", 170, qfalse, r_ext_depth_bounds_test); glConfig2.framebufferObjectAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_EXT_framebuffer_object", 300, qfalse, r_ext_packed_depth_stencil)) { glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glConfig2.maxRenderbufferSize); glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glConfig2.maxColorAttachments); glConfig2.framebufferObjectAvailable = qtrue; } GL_CheckErrors(); glConfig2.framebufferPackedDepthStencilAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_EXT_packed_depth_stencil", 300, qfalse, r_ext_packed_depth_stencil) && glConfig.driverType != GLDRV_MESA) { glConfig2.framebufferPackedDepthStencilAvailable = qtrue; } glConfig2.framebufferBlitAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_EXT_framebuffer_blit", 300, qfalse, r_ext_framebuffer_blit)) { glConfig2.framebufferBlitAvailable = qtrue; } // GL_EXTX_framebuffer_mixed_formats not used glConfig2.generateMipmapAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_SGIS_generate_mipmap", 140, qfalse, r_ext_generate_mipmap)) { glConfig2.generateMipmapAvailable = qtrue; } glConfig2.getProgramBinaryAvailable = qfalse; if (GLimp_CheckForVersionExtension("GL_ARB_get_program_binary", 410, qfalse, NULL)) { int formats = 0; glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &formats); if (formats) { glConfig2.getProgramBinaryAvailable = qtrue; } } // If we are in developer mode, then we will print out messages from the gfx driver if (GLimp_CheckForVersionExtension("GL_ARB_debug_output", 410, qfalse, NULL) && ri.Cvar_VariableIntegerValue("developer")) { #ifdef GL_DEBUG_OUTPUT glEnable(GL_DEBUG_OUTPUT); if (410 <= glConfig2.contextCombined) { glDebugMessageCallback(Glimp_DebugCallback, NULL); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); } else { glDebugMessageCallbackARB(Glimp_DebugCallback, NULL); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); } #endif } }
/* ============ R_CreateVBO2 ============ */ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t *verts, unsigned int stateBits, vboUsage_t usage) { VBO_t *vbo; int i, j; byte *data; int dataSize; int dataOfs; int glUsage; unsigned int bits; switch (usage) { case VBO_USAGE_STATIC: glUsage = GL_STATIC_DRAW; break; case VBO_USAGE_DYNAMIC: glUsage = GL_DYNAMIC_DRAW; break; default: glUsage = 0; Ren_Fatal("bad vboUsage_t given: %i", usage); break; } if (!numVertexes) { return NULL; } if (strlen(name) >= MAX_QPATH) { Ren_Drop("R_CreateVBO2: \"%s\" is too long\n", name); } // make sure the render thread is stopped R_IssuePendingRenderCommands(); vbo = (VBO_t *)ri.Hunk_Alloc(sizeof(*vbo), h_low); Com_AddToGrowList(&tr.vbos, vbo); Q_strncpyz(vbo->name, name, sizeof(vbo->name)); vbo->ofsXYZ = 0; vbo->ofsTexCoords = 0; vbo->ofsLightCoords = 0; vbo->ofsBinormals = 0; vbo->ofsTangents = 0; vbo->ofsNormals = 0; vbo->ofsColors = 0; vbo->ofsPaintColors = 0; vbo->ofsLightDirections = 0; vbo->ofsBoneIndexes = 0; vbo->ofsBoneWeights = 0; vbo->sizeXYZ = 0; vbo->sizeTangents = 0; vbo->sizeBinormals = 0; vbo->sizeNormals = 0; // size VBO dataSize = 0; bits = stateBits; while (bits) { if (bits & 1) { dataSize += sizeof(vec4_t); } bits >>= 1; } dataSize *= numVertexes; data = (byte *)ri.Hunk_AllocateTempMemory(dataSize); dataOfs = 0; // since this is all float, point tmp directly into data // 2-entry -> { memb[0], memb[1], 0, 1 } // 3-entry -> { memb[0], memb[1], memb[2], 1 } #define VERTEXSIZE(memb) (sizeof(verts->memb) / sizeof(verts->memb[0])) #define VERTEXCOPY(memb) \ do { \ vec_t *tmp = (vec_t *) (data + dataOfs); \ for (i = 0; i < numVertexes; i++) \ { \ for (j = 0; j < VERTEXSIZE(memb); j++) { *tmp++ = verts[i].memb[j]; } \ if (VERTEXSIZE(memb) < 3) { *tmp++ = 0; } \ if (VERTEXSIZE(memb) < 4) { *tmp++ = 1; } \ } \ dataOfs += i * sizeof(vec4_t); \ } while (0) if (stateBits & ATTR_POSITION) { vbo->ofsXYZ = dataOfs; VERTEXCOPY(xyz); } // feed vertex texcoords if (stateBits & ATTR_TEXCOORD) { vbo->ofsTexCoords = dataOfs; VERTEXCOPY(st); } // feed vertex lightmap texcoords if (stateBits & ATTR_LIGHTCOORD) { vbo->ofsLightCoords = dataOfs; VERTEXCOPY(lightmap); } // feed vertex tangents if (stateBits & ATTR_TANGENT) { vbo->ofsTangents = dataOfs; VERTEXCOPY(tangent); } // feed vertex binormals if (stateBits & ATTR_BINORMAL) { vbo->ofsBinormals = dataOfs; VERTEXCOPY(binormal); } // feed vertex normals if (stateBits & ATTR_NORMAL) { vbo->ofsNormals = dataOfs; VERTEXCOPY(normal); } // feed vertex colors if (stateBits & ATTR_COLOR) { vbo->ofsColors = dataOfs; VERTEXCOPY(lightColor); } vbo->vertexesSize = dataSize; vbo->vertexesNum = numVertexes; glGenBuffers(1, &vbo->vertexesVBO); glBindBuffer(GL_ARRAY_BUFFER, vbo->vertexesVBO); glBufferData(GL_ARRAY_BUFFER, dataSize, data, glUsage); glBindBuffer(GL_ARRAY_BUFFER, 0); GL_CheckErrors(); ri.Hunk_FreeTempMemory(data); return vbo; }
/** * @brief This routine is responsible for initializing the OS specific portions of OpenGL */ void GLimp_Init(void) { r_allowSoftwareGL = ri.Cvar_Get("r_allowSoftwareGL", "0", CVAR_LATCH); r_allowResize = ri.Cvar_Get("r_allowResize", "0", CVAR_ARCHIVE); r_centerWindow = ri.Cvar_Get("r_centerWindow", "0", CVAR_ARCHIVE); if (ri.Cvar_VariableIntegerValue("com_abnormalExit")) { ri.Cvar_Set("r_mode", va("%d", R_MODE_FALLBACK)); ri.Cvar_Set("r_fullscreen", "0"); ri.Cvar_Set("r_centerWindow", "0"); ri.Cvar_Set("com_abnormalExit", "0"); } ri.Sys_GLimpInit(); // Create the window and set up the context if (GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, r_noborder->integer)) { goto success; } // Try again, this time in a platform specific "safe mode" ri.Sys_GLimpSafeInit(); if (GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, qfalse)) { goto success; } // Finally, try the default screen resolution if (r_mode->integer != R_MODE_FALLBACK) { Ren_Print("Setting r_mode %d failed, falling back on r_mode %d\n", r_mode->integer, R_MODE_FALLBACK); if (GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, qfalse, qfalse)) { goto success; } } // Nothing worked, give up Ren_Fatal("GLimp_Init() - could not load OpenGL subsystem\n"); success: //Clear the screen with a black color thanks Glimp_ClearScreen(); #ifdef FEATURE_RENDERER2 if (glConfig.driverType != GLDRV_OPENGL3) { glConfig.driverType = GLDRV_ICD; } #else // This values force the UI to disable driver selection glConfig.driverType = GLDRV_ICD; #endif glConfig.hardwareType = GLHW_GENERIC; // Only using SDL_SetWindowBrightness to determine if hardware gamma is supported glConfig.deviceSupportsGamma = !r_ignorehwgamma->integer && SDL_SetWindowBrightness(main_window, 1.0f) >= 0; // Get extension strings if (glConfig.driverType != GLDRV_OPENGL3) { Q_strncpyz(glConfig.extensions_string, ( char * ) glGetString(GL_EXTENSIONS), sizeof(glConfig.extensions_string)); } #ifndef FEATURE_RENDERER_GLES else { int i = 0, exts = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &exts); glConfig.extensions_string[0] = 0; for (i = 0; i < exts; i++) { if (strlen(glConfig.extensions_string) + 100 >= sizeof(glConfig.extensions_string)) { //Just so we wont error out when there are really a lot of extensions break; } Q_strcat(glConfig.extensions_string, sizeof(glConfig.extensions_string), va("%s ", glGetStringi(GL_EXTENSIONS, i))); } } #endif // FEATURE_RENDERER_GLES // initialize extensions GLimp_SetHardware(); #ifdef FEATURE_RENDERER2 GLimp_InitExtensionsR2(); // renderer2 #else GLimp_InitExtensions(); // vanilla renderer #endif ri.Cvar_Get("r_availableModes", "", CVAR_ROM); // This depends on SDL_INIT_VIDEO, hence having it here ri.IN_Init(); }
/** * @brief Will be called once for each RE_EndFrame */ void RE_BeginFrame() { drawBufferCommand_t *cmd; if (!tr.registered) { return; } Ren_LogComment("--- RE_BeginFrame ---\n"); glState.finishCalled = qfalse; tr.frameCount++; tr.frameSceneNum = 0; tr.viewCount = 0; // do overdraw measurement if (r_measureOverdraw->integer) { if (glConfig.stencilBits < 4) { Ren_Print("Warning: not enough stencil bits to measure overdraw: %d\n", glConfig.stencilBits); ri.Cvar_Set("r_measureOverdraw", "0"); } else if (r_shadows->integer == 2) { Ren_Print("Warning: stencil shadows and overdraw measurement are mutually exclusive\n"); ri.Cvar_Set("r_measureOverdraw", "0"); } else { R_IssuePendingRenderCommands(); glEnable(GL_STENCIL_TEST); glStencilMask(~0U); GL_ClearStencil(0U); glStencilFunc(GL_ALWAYS, 0U, ~0U); glStencilOp(GL_KEEP, GL_INCR, GL_INCR); } r_measureOverdraw->modified = qfalse; } else { // this is only reached if it was on and is now off if (r_measureOverdraw->modified) { R_IssuePendingRenderCommands(); glDisable(GL_STENCIL_TEST); } r_measureOverdraw->modified = qfalse; } // texturemode stuff if (r_textureMode->modified) { R_IssuePendingRenderCommands(); GL_TextureMode(r_textureMode->string); r_textureMode->modified = qfalse; } // gamma stuff if (r_gamma->modified) { r_gamma->modified = qfalse; R_IssuePendingRenderCommands(); R_SetColorMappings(); } // check for errors if (!r_ignoreGLErrors->integer) { int err; char s[128]; R_IssuePendingRenderCommands(); if ((err = glGetError()) != GL_NO_ERROR) { switch (err) { case GL_INVALID_ENUM: Q_strcpy(s, "GL_INVALID_ENUM"); break; case GL_INVALID_VALUE: Q_strcpy(s, "GL_INVALID_VALUE"); break; case GL_INVALID_OPERATION: Q_strcpy(s, "GL_INVALID_OPERATION"); break; case GL_STACK_OVERFLOW: Q_strcpy(s, "GL_STACK_OVERFLOW"); break; case GL_STACK_UNDERFLOW: Q_strcpy(s, "GL_STACK_UNDERFLOW"); break; case GL_OUT_OF_MEMORY: Q_strcpy(s, "GL_OUT_OF_MEMORY"); break; case GL_TABLE_TOO_LARGE: Q_strcpy(s, "GL_TABLE_TOO_LARGE"); break; case GL_INVALID_FRAMEBUFFER_OPERATION_EXT: Q_strcpy(s, "GL_INVALID_FRAMEBUFFER_OPERATION_EXT"); break; default: Com_sprintf(s, sizeof(s), "0x%X", err); break; } //Ren_Fatal( "caught OpenGL error: %s in file %s line %i", s, filename, line); Ren_Fatal("RE_BeginFrame() - glGetError() failed (%s)!\n", s); } } // draw buffer stuff cmd = (drawBufferCommand_t *)R_GetCommandBuffer(sizeof(*cmd)); if (!cmd) { return; } cmd->commandId = RC_DRAW_BUFFER; if (!Q_stricmp(r_drawBuffer->string, "GL_FRONT")) { cmd->buffer = (int)GL_FRONT; } else { cmd->buffer = (int)GL_BACK; } }
static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) { int perChannelColorBits; int colorBits, depthBits, stencilBits; int samples; int i = 0; SDL_Surface *icon = NULL; SDL_DisplayMode desktopMode; int display = 0; int x = SDL_WINDOWPOS_UNDEFINED, y = SDL_WINDOWPOS_UNDEFINED; Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_GRABBED; #ifndef FEATURE_RENDERER_GLES GLenum glewResult; #endif Ren_Print("Initializing OpenGL display\n"); if (r_allowResize->integer && !fullscreen) { flags |= SDL_WINDOW_RESIZABLE; } icon = SDL_CreateRGBSurfaceFrom( (void *)CLIENT_WINDOW_ICON.pixel_data, CLIENT_WINDOW_ICON.width, CLIENT_WINDOW_ICON.height, CLIENT_WINDOW_ICON.bytes_per_pixel * 8, CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width, #ifdef Q3_LITTLE_ENDIAN 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 #else 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF #endif ); // If a window exists, note its display index if (main_window != NULL) { display = SDL_GetWindowDisplayIndex(main_window); } if (SDL_GetDesktopDisplayMode(display, &desktopMode) == 0) { displayAspect = (float)desktopMode.w / (float)desktopMode.h; Ren_Print("Estimated display aspect: %.3f\n", displayAspect); } else { Com_Memset(&desktopMode, 0, sizeof(SDL_DisplayMode)); Ren_Print("Cannot estimate display aspect, assuming 1.333\n"); } Ren_Print("...setting mode %d: ", mode); if (mode == -2) { // use desktop video resolution if (desktopMode.h > 0) { glConfig.vidWidth = desktopMode.w; glConfig.vidHeight = desktopMode.h; } else { glConfig.vidWidth = 640; glConfig.vidHeight = 480; Ren_Print("Cannot determine display resolution, assuming 640x480\n"); } glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight; } else if (!R_GetModeInfo(&glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode)) { Ren_Print("invalid mode\n"); return RSERR_INVALID_MODE; } Ren_Print("%dx%d\n", glConfig.vidWidth, glConfig.vidHeight); // Center window if (r_centerWindow->integer && !fullscreen) { x = (desktopMode.w / 2) - (glConfig.vidWidth / 2); y = (desktopMode.h / 2) - (glConfig.vidHeight / 2); } // Destroy existing state if it exists if (SDL_glContext != NULL) { SDL_GL_DeleteContext(SDL_glContext); SDL_glContext = NULL; } if (main_window != NULL) { SDL_GetWindowPosition(main_window, &x, &y); Ren_Developer("Existing window at %dx%d before being destroyed\n", x, y); SDL_DestroyWindow(main_window); main_window = NULL; } if (fullscreen) { if (r_mode->integer == -2) { flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } else { flags |= SDL_WINDOW_FULLSCREEN; } glConfig.isFullscreen = qtrue; } else { if (noborder) { flags |= SDL_WINDOW_BORDERLESS; } glConfig.isFullscreen = qfalse; } colorBits = r_colorbits->value; if ((!colorBits) || (colorBits >= 32)) { colorBits = 24; } if (!r_depthbits->value) { depthBits = 24; } else { depthBits = r_depthbits->value; } stencilBits = r_stencilbits->value; samples = r_ext_multisample->value; for (i = 0; i < 16; i++) { int testColorBits, testDepthBits, testStencilBits; // 0 - default // 1 - minus colorBits // 2 - minus depthBits // 3 - minus stencil if ((i % 4) == 0 && i) { // one pass, reduce switch (i / 4) { case 2: if (colorBits == 24) { colorBits = 16; } break; case 1: if (depthBits == 32) { depthBits = 24; } else if (depthBits == 24) { depthBits = 16; } else if (depthBits == 16) { depthBits = 8; } case 3: // fall through if (stencilBits == 24) { stencilBits = 16; } else if (stencilBits == 16) { stencilBits = 8; } } } testColorBits = colorBits; testDepthBits = depthBits; testStencilBits = stencilBits; if ((i % 4) == 3) // reduce colorbits { if (testColorBits == 24) { testColorBits = 16; } } if ((i % 4) == 2) // reduce depthbits { if (testDepthBits == 24) { testDepthBits = 16; } else if (testDepthBits == 16) { testDepthBits = 8; } } if ((i % 4) == 1) // reduce stencilbits { if (testStencilBits == 24) { testStencilBits = 16; } else if (testStencilBits == 16) { testStencilBits = 8; } else { testStencilBits = 0; } } if (testColorBits == 24) { perChannelColorBits = 8; } else { perChannelColorBits = 4; } #ifdef __sgi // Fix for SGIs grabbing too many bits of color if (perChannelColorBits == 4) { perChannelColorBits = 0; /* Use minimum size for 16-bit color */ } // Need alpha or else SGIs choose 36+ bit RGB mode SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 1); #endif SDL_GL_SetAttribute(SDL_GL_RED_SIZE, perChannelColorBits); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, perChannelColorBits); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, perChannelColorBits); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, testDepthBits); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, testStencilBits); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples); // SDL2 uses opengl by default, if we want opengl es we need to set this attribute //SDL_GL_SetAttribute(SDL_GL_CONTEXT_EGL, 1); if (r_stereoEnabled->integer) { glConfig.stereoEnabled = qtrue; SDL_GL_SetAttribute(SDL_GL_STEREO, 1); } else { glConfig.stereoEnabled = qfalse; SDL_GL_SetAttribute(SDL_GL_STEREO, 0); } SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // If not allowing software GL, demand accelerated if (!r_allowSoftwareGL->integer) { SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); } main_window = SDL_CreateWindow(CLIENT_WINDOW_TITLE, x, y, glConfig.vidWidth, glConfig.vidHeight, flags | SDL_WINDOW_SHOWN); if (!main_window) { Ren_Developer("SDL_CreateWindow failed: %s\n", SDL_GetError()); continue; } //This is disabled since at least now we have no use for this /* if (!Glimp_Create2DRenderer(main_window)) { continue; } */ if (fullscreen) { SDL_DisplayMode mode; switch (testColorBits) { case 16: mode.format = SDL_PIXELFORMAT_RGB565; break; case 24: mode.format = SDL_PIXELFORMAT_RGB24; break; default: Ren_Developer("testColorBits is %d, can't fullscreen\n", testColorBits); continue; } mode.w = glConfig.vidWidth; mode.h = glConfig.vidHeight; mode.refresh_rate = glConfig.displayFrequency = ri.Cvar_VariableIntegerValue("r_displayRefresh"); mode.driverdata = NULL; if (SDL_SetWindowDisplayMode(main_window, &mode) < 0) { Ren_Developer("SDL_SetWindowDisplayMode failed: %s\n", SDL_GetError()); continue; } } SDL_SetWindowIcon(main_window, icon); #if defined(FEATURE_RENDERER2) glewExperimental = GL_TRUE; SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); #endif if ((SDL_glContext = SDL_GL_CreateContext(main_window)) == NULL) { Ren_Developer("SDL_GL_CreateContext failed: %s\n", SDL_GetError()); continue; } SDL_GL_MakeCurrent(main_window, SDL_glContext); SDL_GL_SetSwapInterval(r_swapInterval->integer); glConfig.colorBits = testColorBits; glConfig.depthBits = testDepthBits; glConfig.stencilBits = testStencilBits; ri.Printf(PRINT_ALL, "Using %d color bits, %d depth, %d stencil display.\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits); break; } GLimp_DetectAvailableModes(); #if !defined(FEATURE_RENDERER_GLES) glewResult = glewInit(); if (GLEW_OK != glewResult) { // glewInit failed, something is seriously wrong Ren_Fatal("GLW_StartOpenGL() - could not load OpenGL subsystem: %s", glewGetErrorString(glewResult)); } else { Ren_Print("Using GLEW %s\n", glewGetString(GLEW_VERSION)); } #endif if (!GLimp_InitOpenGLContext()) { return RSERR_OLD_GL; } if (!main_window) //|| !main_renderer) { Ren_Print("Couldn't get a visual\n"); return RSERR_INVALID_MODE; } SDL_FreeSurface(icon); return RSERR_OK; }