void piglit_init(int argc, char **argv) { /* test some new error cases */ GLuint fbo, tex; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, tex); glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 4, GL_RGBA, 64, 64, 2, GL_TRUE); if (!piglit_check_gl_error(GL_NO_ERROR)) { printf("should be no error so far\n"); piglit_report_result(PIGLIT_FAIL); } /* binding a negative layer should fail */ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, -1); if (!piglit_check_gl_error(GL_INVALID_VALUE)) { printf("glFramebufferTextureLayer w/ negative layer must " "emit GL_INVALID_VALUE but did not\n"); piglit_report_result(PIGLIT_FAIL); } piglit_report_result(PIGLIT_PASS); }
bool Texture::upload(const unsigned char *source, const int mipLevel) const { glBindTexture(target, glId); GL_CHECK_ERRORS(); switch (target) { case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, multisamples, internalFormat, width, height, layers, GL_TRUE); break; case GL_TEXTURE_2D_MULTISAMPLE: glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, multisamples, internalFormat, width, height, GL_TRUE); break; case GL_TEXTURE_3D: glTexImage3D(GL_TEXTURE_3D, mipLevel, internalFormat, width, height, depth, 0, format, precision, source); break; case GL_TEXTURE_2D: glTexImage2D(GL_TEXTURE_2D, mipLevel, internalFormat, width, height, 0, format, precision, source); break; case GL_TEXTURE_1D: glTexImage1D(GL_TEXTURE_1D, mipLevel, internalFormat, width, 0, format, precision, source); break; case GL_TEXTURE_2D_ARRAY: glTexImage3D(GL_TEXTURE_2D_ARRAY, mipLevel, internalFormat, width, height, layers, 0, format, precision, source); break; case GL_TEXTURE_1D_ARRAY: glTexImage2D(GL_TEXTURE_1D_ARRAY, mipLevel, internalFormat, width, height, 0, format, precision, source); break; default: cout << "Invalid texture format: 0x" << hex << target << dec << endl; return false; } GL_CHECK_ERRORS(); return true; }
void QOpenGLTextureHelper::qt_TextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) { GLint oldTexture; glGetIntegerv(bindingTarget, &oldTexture); glBindTexture(target, texture); glTexImage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); glBindTexture(target, oldTexture); }
GLuint create_bind_texture(GLenum textureType) { int i; GLuint texture; glGenTextures(1, &texture); glBindTexture(textureType, texture); switch(textureType) { case GL_TEXTURE_1D: glTexParameteri(textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(textureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(textureType, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(textureType, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage1D(textureType, 0, GL_RGBA, 6, 0, GL_RGBA, GL_UNSIGNED_INT, NULL); break; case GL_TEXTURE_RECTANGLE: glTexImage2D(textureType, 0, GL_RGBA, 6, 6, 0, GL_RGBA, GL_UNSIGNED_INT, NULL); break; case GL_TEXTURE_2D: case GL_TEXTURE_1D_ARRAY: glTexParameteri(textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(textureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(textureType, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(textureType, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexImage2D(textureType, 0, GL_RGBA, 6, 6, 0, GL_RGBA, GL_UNSIGNED_INT, NULL); break; case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: glTexParameteri(textureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(textureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(textureType, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(textureType, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(textureType, GL_TEXTURE_WRAP_R, GL_REPEAT); glTexImage3D(textureType, 0, GL_RGBA, 6, 6, 6, 0, GL_RGBA, GL_UNSIGNED_INT, NULL); break; case GL_TEXTURE_CUBE_MAP: for(i = 0; i < 6; i++) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, 6, 6, 0, GL_RGBA, GL_UNSIGNED_INT, NULL); } break; case GL_TEXTURE_2D_MULTISAMPLE: glTexImage2DMultisample(textureType, 1, GL_RGBA, 6, 6, GL_FALSE); break; case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: glTexImage3DMultisample(textureType, 1, GL_RGBA, 6, 6, 6, GL_FALSE); break; } return texture; }
FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples) { m_xfbFramebuffer = 0; m_efbColor = 0; m_efbDepth = 0; m_efbColorSwap = 0; m_resolvedColorTexture = 0; m_resolvedDepthTexture = 0; m_targetWidth = targetWidth; m_targetHeight = targetHeight; m_msaaSamples = msaaSamples; // The EFB can be set to different pixel formats by the game through the // BPMEM_ZCOMPARE register (which should probably have a different name). // They are: // - 24-bit RGB (8-bit components) with 24-bit Z // - 24-bit RGBA (6-bit components) with 24-bit Z // - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z // We only use one EFB format here: 32-bit ARGB with 24-bit Z. // Multisampling depends on user settings. // The distinction becomes important for certain operations, i.e. the // alpha channel should be ignored if the EFB does not have one. glActiveTexture(GL_TEXTURE9); GLuint glObj[3]; glGenTextures(3, glObj); m_efbColor = glObj[0]; m_efbDepth = glObj[1]; m_efbColorSwap = glObj[2]; m_EFBLayers = (g_ActiveConfig.iStereoMode > 0) ? 2 : 1; m_efbFramebuffer.resize(m_EFBLayers); m_resolvedFramebuffer.resize(m_EFBLayers); // OpenGL MSAA textures are a different kind of texture type and must be allocated // with a different function, so we create them separately. if (m_msaaSamples <= 1) { m_textureType = GL_TEXTURE_2D_ARRAY; glBindTexture(m_textureType, m_efbColor); glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0); glTexImage3D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glBindTexture(m_textureType, m_efbDepth); glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0); glTexImage3D(m_textureType, 0, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); glBindTexture(m_textureType, m_efbColorSwap); glTexParameteri(m_textureType, GL_TEXTURE_MAX_LEVEL, 0); glTexImage3D(m_textureType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } else { GLenum resolvedType = GL_TEXTURE_2D_ARRAY; // Only use a layered multisample texture if needed. Some drivers // slow down significantly with single-layered multisample textures. if (m_EFBLayers > 1) { m_textureType = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; if (g_ogl_config.bSupports3DTextureStorage) { glBindTexture(m_textureType, m_efbColor); glTexStorage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight, m_EFBLayers, false); glBindTexture(m_textureType, m_efbDepth); glTexStorage3DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, m_EFBLayers, false); glBindTexture(m_textureType, m_efbColorSwap); glTexStorage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight, m_EFBLayers, false); glBindTexture(m_textureType, 0); } else { glBindTexture(m_textureType, m_efbColor); glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false); glBindTexture(m_textureType, m_efbDepth); glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, m_EFBLayers, false); glBindTexture(m_textureType, m_efbColorSwap); glTexImage3DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, false); glBindTexture(m_textureType, 0); } } else { m_textureType = GL_TEXTURE_2D_MULTISAMPLE; if (g_ogl_config.bSupports2DTextureStorage) { glBindTexture(m_textureType, m_efbColor); glTexStorage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight, false); glBindTexture(m_textureType, m_efbDepth); glTexStorage2DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, false); glBindTexture(m_textureType, m_efbColorSwap); glTexStorage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight, false); glBindTexture(m_textureType, 0); } else { glBindTexture(m_textureType, m_efbColor); glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, false); glBindTexture(m_textureType, m_efbDepth); glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, false); glBindTexture(m_textureType, m_efbColorSwap); glTexImage2DMultisample(m_textureType, m_msaaSamples, GL_RGBA, m_targetWidth, m_targetHeight, false); glBindTexture(m_textureType, 0); } } // Although we are able to access the multisampled texture directly, we don't do it everywhere. // The old way is to "resolve" this multisampled texture by copying it into a non-sampled // texture. // This would lead to an unneeded copy of the EFB, so we are going to avoid it. // But as this job isn't done right now, we do need that texture for resolving: glGenTextures(2, glObj); m_resolvedColorTexture = glObj[0]; m_resolvedDepthTexture = glObj[1]; glBindTexture(resolvedType, m_resolvedColorTexture); glTexParameteri(resolvedType, GL_TEXTURE_MAX_LEVEL, 0); glTexImage3D(resolvedType, 0, GL_RGBA, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glBindTexture(resolvedType, m_resolvedDepthTexture); glTexParameteri(resolvedType, GL_TEXTURE_MAX_LEVEL, 0); glTexImage3D(resolvedType, 0, GL_DEPTH_COMPONENT32F, m_targetWidth, m_targetHeight, m_EFBLayers, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); // Bind resolved textures to resolved framebuffer. glGenFramebuffers(m_EFBLayers, m_resolvedFramebuffer.data()); glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer[0]); FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, resolvedType, m_resolvedColorTexture, 0); FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, resolvedType, m_resolvedDepthTexture, 0); // Bind all the other layers as separate FBOs for blitting. for (unsigned int i = 1; i < m_EFBLayers; i++) { glBindFramebuffer(GL_FRAMEBUFFER, m_resolvedFramebuffer[i]); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_resolvedColorTexture, 0, i); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_resolvedDepthTexture, 0, i); } } // Create XFB framebuffer; targets will be created elsewhere. glGenFramebuffers(1, &m_xfbFramebuffer); // Bind target textures to EFB framebuffer. glGenFramebuffers(m_EFBLayers, m_efbFramebuffer.data()); glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0); FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_textureType, m_efbDepth, 0); // Bind all the other layers as separate FBOs for blitting. for (unsigned int i = 1; i < m_EFBLayers; i++) { glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[i]); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_efbColor, 0, i); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_efbDepth, 0, i); } // EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f glViewport(0, 0, m_targetWidth, m_targetHeight); glScissor(0, 0, m_targetWidth, m_targetHeight); glClearColor(0.f, 0.f, 0.f, 1.f); glClearDepthf(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // reinterpret pixel format const char* vs = m_EFBLayers > 1 ? "void main(void) {\n" " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" "}\n" : "flat out int layer;\n" "void main(void) {\n" " layer = 0;\n" " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" "}\n"; // The way to sample the EFB is based on the on the current configuration. // As we use the same sampling way for both interpreting shaders, the sampling // shader are generated first: std::string sampler; if (m_msaaSamples <= 1) { // non-msaa, so just fetch the pixel sampler = "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" "vec4 sampleEFB(ivec3 pos) {\n" " return texelFetch(samp9, pos, 0);\n" "}\n"; } else if (g_ActiveConfig.backend_info.bSupportsSSAA) { // msaa + sample shading available, so just fetch the sample // This will lead to sample shading, but it's the only way to not loose // the values of each sample. if (m_EFBLayers > 1) { sampler = "SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;\n" "vec4 sampleEFB(ivec3 pos) {\n" " return texelFetch(samp9, pos, gl_SampleID);\n" "}\n"; } else { sampler = "SAMPLER_BINDING(9) uniform sampler2DMS samp9;\n" "vec4 sampleEFB(ivec3 pos) {\n" " return texelFetch(samp9, pos.xy, gl_SampleID);\n" "}\n"; } } else { // msaa without sample shading: calculate the mean value of the pixel std::stringstream samples; samples << m_msaaSamples; if (m_EFBLayers > 1) { sampler = "SAMPLER_BINDING(9) uniform sampler2DMSArray samp9;\n" "vec4 sampleEFB(ivec3 pos) {\n" " vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n" " for(int i=0; i<" + samples.str() + "; i++)\n" " color += texelFetch(samp9, pos, i);\n" " return color / " + samples.str() + ";\n" "}\n"; } else { sampler = "SAMPLER_BINDING(9) uniform sampler2DMS samp9;\n" "vec4 sampleEFB(ivec3 pos) {\n" " vec4 color = vec4(0.0, 0.0, 0.0, 0.0);\n" " for(int i=0; i<" + samples.str() + "; i++)\n" " color += texelFetch(samp9, pos.xy, i);\n" " return color / " + samples.str() + ";\n" "}\n"; } } std::string ps_rgba6_to_rgb8 = sampler + "flat in int layer;\n" "out vec4 ocol0;\n" "void main()\n" "{\n" " ivec4 src6 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 63.f));\n" " ivec4 dst8;\n" " dst8.r = (src6.r << 2) | (src6.g >> 4);\n" " dst8.g = ((src6.g & 0xF) << 4) | (src6.b >> 2);\n" " dst8.b = ((src6.b & 0x3) << 6) | src6.a;\n" " dst8.a = 255;\n" " ocol0 = float4(dst8) / 255.f;\n" "}"; std::string ps_rgb8_to_rgba6 = sampler + "flat in int layer;\n" "out vec4 ocol0;\n" "void main()\n" "{\n" " ivec4 src8 = ivec4(round(sampleEFB(ivec3(gl_FragCoord.xy, layer)) * 255.f));\n" " ivec4 dst6;\n" " dst6.r = src8.r >> 2;\n" " dst6.g = ((src8.r & 0x3) << 4) | (src8.g >> 4);\n" " dst6.b = ((src8.g & 0xF) << 2) | (src8.b >> 6);\n" " dst6.a = src8.b & 0x3F;\n" " ocol0 = float4(dst6) / 63.f;\n" "}"; std::stringstream vertices, layers; vertices << m_EFBLayers * 3; layers << m_EFBLayers; std::string gs = "layout(triangles) in;\n" "layout(triangle_strip, max_vertices = " + vertices.str() + ") out;\n" "flat out int layer;\n" "void main()\n" "{\n" " for (int j = 0; j < " + layers.str() + "; ++j) {\n" " for (int i = 0; i < 3; ++i) {\n" " layer = j;\n" " gl_Layer = j;\n" " gl_Position = gl_in[i].gl_Position;\n" " EmitVertex();\n" " }\n" " EndPrimitive();\n" " }\n" "}\n"; ProgramShaderCache::CompileShader(m_pixel_format_shaders[0], vs, ps_rgb8_to_rgba6.c_str(), (m_EFBLayers > 1) ? gs : ""); ProgramShaderCache::CompileShader(m_pixel_format_shaders[1], vs, ps_rgba6_to_rgb8.c_str(), (m_EFBLayers > 1) ? gs : ""); ProgramShaderCache::CompileShader( m_EfbPokes, StringFromFormat("in vec2 rawpos;\n" "in vec4 color0;\n" // color "in int color1;\n" // depth "out vec4 v_c;\n" "out float v_z;\n" "void main(void) {\n" " gl_Position = vec4(((rawpos + 0.5) / vec2(640.0, 528.0) * 2.0 - 1.0) * " "vec2(1.0, -1.0), 0.0, 1.0);\n" " gl_PointSize = %d.0 / 640.0;\n" " v_c = color0.bgra;\n" " v_z = float(color1 & 0xFFFFFF) / 16777216.0;\n" "}\n", m_targetWidth), StringFromFormat("in vec4 %s_c;\n" "in float %s_z;\n" "out vec4 ocol0;\n" "void main(void) {\n" " ocol0 = %s_c;\n" " gl_FragDepth = %s_z;\n" "}\n", m_EFBLayers > 1 ? "g" : "v", m_EFBLayers > 1 ? "g" : "v", m_EFBLayers > 1 ? "g" : "v", m_EFBLayers > 1 ? "g" : "v"), m_EFBLayers > 1 ? StringFromFormat("layout(points) in;\n" "layout(points, max_vertices = %d) out;\n" "in vec4 v_c[1];\n" "in float v_z[1];\n" "out vec4 g_c;\n" "out float g_z;\n" "void main()\n" "{\n" " for (int j = 0; j < %d; ++j) {\n" " gl_Layer = j;\n" " gl_Position = gl_in[0].gl_Position;\n" " gl_PointSize = %d.0 / 640.0;\n" " g_c = v_c[0];\n" " g_z = v_z[0];\n" " EmitVertex();\n" " EndPrimitive();\n" " }\n" "}\n", m_EFBLayers, m_EFBLayers, m_targetWidth) : ""); glGenBuffers(1, &m_EfbPokes_VBO); glGenVertexArrays(1, &m_EfbPokes_VAO); glBindBuffer(GL_ARRAY_BUFFER, m_EfbPokes_VBO); glBindVertexArray(m_EfbPokes_VAO); glEnableVertexAttribArray(SHADER_POSITION_ATTRIB); glVertexAttribPointer(SHADER_POSITION_ATTRIB, 2, GL_UNSIGNED_SHORT, 0, sizeof(EfbPokeData), (void*)offsetof(EfbPokeData, x)); glEnableVertexAttribArray(SHADER_COLOR0_ATTRIB); glVertexAttribPointer(SHADER_COLOR0_ATTRIB, 4, GL_UNSIGNED_BYTE, 1, sizeof(EfbPokeData), (void*)offsetof(EfbPokeData, data)); glEnableVertexAttribArray(SHADER_COLOR1_ATTRIB); glVertexAttribIPointer(SHADER_COLOR1_ATTRIB, 1, GL_INT, sizeof(EfbPokeData), (void*)offsetof(EfbPokeData, data)); if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) glEnable(GL_PROGRAM_POINT_SIZE); }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_GL32_nglTexImage3DMultisample(JNIEnv *env, jclass clazz, jint target, jint samples, jint internalformat, jint width, jint height, jint depth, jboolean fixedsamplelocations, jlong function_pointer) { glTexImage3DMultisamplePROC glTexImage3DMultisample = (glTexImage3DMultisamplePROC)((intptr_t)function_pointer); glTexImage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations); }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_ARBTextureMultisample_glTexImage3DMultisample(JNIEnv *__env, jclass clazz, jint target, jint samples, jint internalformat, jint width, jint height, jint depth, jboolean fixedsamplelocations) { glTexImage3DMultisamplePROC glTexImage3DMultisample = (glTexImage3DMultisamplePROC)tlsGetFunction(654); UNUSED_PARAM(clazz) glTexImage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations); }
bool upload_image_levels(const struct image_info img, unsigned num_levels, unsigned level, unsigned unit, const uint32_t *pixels) { const unsigned m = image_num_components(img.format); int i, l; if (get_texture(unit)) { glDeleteTextures(1, &textures[unit]); textures[unit] = 0; } if (get_buffer(unit)) { glDeleteBuffers(1, &buffers[unit]); buffers[unit] = 0; } glGenTextures(1, &textures[unit]); glBindTexture(img.target->target, textures[unit]); switch (img.target->target) { case GL_TEXTURE_1D: for (l = 0; l < num_levels; ++l) { const struct image_extent size = image_level_size(img, l); glTexImage1D(GL_TEXTURE_1D, l, img.format->format, size.x, 0, img.format->pixel_format, image_base_type(img.format), &pixels[m * image_level_offset(img, l)]); } break; case GL_TEXTURE_2D: for (l = 0; l < num_levels; ++l) { const struct image_extent size = image_level_size(img, l); glTexImage2D(GL_TEXTURE_2D, l, img.format->format, size.x, size.y, 0, img.format->pixel_format, image_base_type(img.format), &pixels[m * image_level_offset(img, l)]); } break; case GL_TEXTURE_3D: for (l = 0; l < num_levels; ++l) { const struct image_extent size = image_level_size(img, l); glTexImage3D(GL_TEXTURE_3D, l, img.format->format, size.x, size.y, size.z, 0, img.format->pixel_format, image_base_type(img.format), &pixels[m * image_level_offset(img, l)]); } break; case GL_TEXTURE_RECTANGLE: assert(num_levels == 1); glTexImage2D(GL_TEXTURE_RECTANGLE, 0, img.format->format, img.size.x, img.size.y, 0, img.format->pixel_format, image_base_type(img.format), pixels); break; case GL_TEXTURE_CUBE_MAP: for (l = 0; l < num_levels; ++l) { const unsigned offset = m * image_level_offset(img, l); const struct image_extent size = image_level_size(img, l); const unsigned face_sz = m * product(size) / 6; for (i = 0; i < 6; ++i) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, l, img.format->format, size.x, size.y, 0, img.format->pixel_format, image_base_type(img.format), &pixels[offset + face_sz * i]); } break; case GL_TEXTURE_BUFFER: { /* * glTexImage*() isn't supposed to work with buffer * textures. We copy the unpacked pixels to a texture * with the desired internal format to let the GL pack * them for us. */ const struct image_extent grid = image_optimal_extent(img.size); GLuint packed_tex; assert(num_levels == 1); glGenBuffers(1, &buffers[unit]); glBindBuffer(GL_PIXEL_PACK_BUFFER, buffers[unit]); glBufferData(GL_PIXEL_PACK_BUFFER, img.size.x * image_pixel_size(img.format) / 8, NULL, GL_STATIC_DRAW); glGenTextures(1, &packed_tex); glBindTexture(GL_TEXTURE_2D, packed_tex); glTexImage2D(GL_TEXTURE_2D, 0, img.format->format, grid.x, grid.y, 0, img.format->pixel_format, image_base_type(img.format), pixels); glGetTexImage(GL_TEXTURE_2D, 0, img.format->pixel_format, img.format->pixel_type, NULL); glDeleteTextures(1, &packed_tex); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glTexBuffer(GL_TEXTURE_BUFFER, image_compat_format(img.format), buffers[unit]); break; } case GL_TEXTURE_1D_ARRAY: for (l = 0; l < num_levels; ++l) { const struct image_extent size = image_level_size(img, l); glTexImage2D(GL_TEXTURE_1D_ARRAY, l, img.format->format, size.x, size.y, 0, img.format->pixel_format, image_base_type(img.format), &pixels[m * image_level_offset(img, l)]); } break; case GL_TEXTURE_2D_ARRAY: for (l = 0; l < num_levels; ++l) { const struct image_extent size = image_level_size(img, l); glTexImage3D(GL_TEXTURE_2D_ARRAY, l, img.format->format, size.x, size.y, size.z, 0, img.format->pixel_format, image_base_type(img.format), &pixels[m * image_level_offset(img, l)]); } break; case GL_TEXTURE_CUBE_MAP_ARRAY: for (l = 0; l < num_levels; ++l) { const struct image_extent size = image_level_size(img, l); glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, l, img.format->format, size.x, size.y, size.z, 0, img.format->pixel_format, image_base_type(img.format), &pixels[m * image_level_offset(img, l)]); } break; case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: { /* * GL doesn't seem to provide any direct way to * initialize a multisample texture, so we use * imageStore() to render to it from the fragment * shader copying the contents of a larger * single-sample 2D texture. */ const struct grid_info grid = { get_image_stage(GL_FRAGMENT_SHADER)->bit, img.format, image_optimal_extent(img.size) }; GLuint prog = generate_program( grid, GL_FRAGMENT_SHADER, concat(image_hunk(image_info_for_grid(grid), "SRC_"), image_hunk(img, "DST_"), hunk("readonly SRC_IMAGE_UNIFORM_T src_img;\n" "writeonly DST_IMAGE_UNIFORM_T dst_img;\n" "\n" "GRID_T op(ivec2 idx, GRID_T x) {\n" " imageStore(dst_img, DST_IMAGE_ADDR(idx),\n" " imageLoad(src_img, SRC_IMAGE_ADDR(idx)));\n" " return x;\n" "}\n"), NULL)); bool ret = prog && generate_fb(grid, 1); GLuint tmp_tex; assert(num_levels == 1); glGenTextures(1, &tmp_tex); glBindTexture(GL_TEXTURE_2D, tmp_tex); if (img.target->target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, img.size.x, img.format->format, img.size.y, img.size.z, img.size.w, GL_FALSE); } else { glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, img.size.x, img.format->format, img.size.y, img.size.z, GL_FALSE); } glTexImage2D(GL_TEXTURE_2D, 0, img.format->format, grid.size.x, grid.size.y, 0, img.format->pixel_format, image_base_type(img.format), pixels); glBindImageTexture(unit, textures[unit], 0, GL_TRUE, 0, GL_WRITE_ONLY, img.format->format); glBindImageTexture(6, tmp_tex, 0, GL_TRUE, 0, GL_READ_ONLY, img.format->format); ret &= set_uniform_int(prog, "src_img", 6) && set_uniform_int(prog, "dst_img", unit) && draw_grid(grid, prog); glDeleteProgram(prog); glDeleteTextures(1, &tmp_tex); glBindFramebuffer(GL_FRAMEBUFFER, fb[0]); glViewportIndexedfv(0, vp[0]); glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); if (!ret) return false; break; } default: abort(); } glBindImageTexture(unit, textures[unit], level, GL_TRUE, 0, GL_READ_WRITE, img.format->format); return piglit_check_gl_error(GL_NO_ERROR); }
/** * Load a miplevel's texel data via glTexImage. * * \param level The miplevel to be loaded (0 <= level <= miplevels) * \param level_image The data to be loaded. * * This function assumes that select_sampler() and compute_miplevel_info() * have already been called. */ void upload_miplevel_data(GLenum target, int level, void *level_image) { const GLenum format = sampler.format; const GLenum internal_format = sampler.internal_format; const GLenum data_type = sampler.data_type; GLuint bo; switch (target) { case GL_TEXTURE_1D: glTexImage1D(GL_TEXTURE_1D, level, internal_format, level_size[level][0], 0, format, data_type, level_image); break; case GL_TEXTURE_2D: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: glTexImage2D(target, level, internal_format, level_size[level][0], level_size[level][1], 0, format, data_type, level_image); break; case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: glTexImage3D(target, level, internal_format, level_size[level][0], level_size[level][1], level_size[level][2], 0, format, data_type, level_image); break; case GL_TEXTURE_1D_ARRAY: glTexImage2D(GL_TEXTURE_1D_ARRAY, level, internal_format, level_size[level][0], level_size[level][2], 0, format, data_type, level_image); break; case GL_TEXTURE_BUFFER: glGenBuffers(1, &bo); glBindBuffer(GL_TEXTURE_BUFFER, bo); glBufferData(GL_TEXTURE_BUFFER, 16 * level_size[level][0], level_image, GL_STATIC_DRAW); glTexBuffer(GL_TEXTURE_BUFFER, internal_format, bo); break; case GL_TEXTURE_2D_MULTISAMPLE: glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, internal_format, level_size[level][0], level_size[level][1], GL_TRUE); break; case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 4, internal_format, level_size[level][0], level_size[level][1], level_size[level][2], GL_TRUE); break; default: assert(!"Not implemented yet."); break; } }
/* * Some GetInternalformati*v pnames returns the same that * GetTexParameter and GetTexLevelParameter. In order to use those, a * texture is needed to be bound. This method creates and bind one * texture based on @target and @internalformat. It returns the * texture name on @tex_out. If target is GL_TEXTURE_BUFFER, a buffer * is also needed, and returned on @buffer_out. Caller is responsible * to free both if the call is successful. * * The type and format to be used to create the texture is any one * valid for the given @internalformat. * * For texture targets, we also use this function to check if the /resource/ * (defined in the ARB_internalformat_query2 spec as an object of the * appropriate type that has been created with <internalformat> and <target>) * is supported by the implementation. If the texture creation fails, then the * resource is unsupported. * * Returns true if it was possible to create the texture. False * otherwise (unsupported /resource/). * */ bool create_texture(const GLenum target, const GLenum internalformat, GLuint *tex_out, GLuint *buffer_out) { GLuint tex = 0; GLuint buffer = 0; GLenum type = type_for_internalformat(internalformat); GLenum format = format_for_internalformat(internalformat); bool result = true; int height = 16; int width = 16; int depth = 16; unsigned i; glGenTextures(1, &tex); glBindTexture(target, tex); switch(target) { case GL_TEXTURE_1D: glTexImage1D(target, 0, internalformat, width, 0, format, type, NULL); break; case GL_TEXTURE_1D_ARRAY: case GL_TEXTURE_2D: case GL_TEXTURE_RECTANGLE: glTexImage2D(target, 0, internalformat, width, height, 0, format, type, NULL); break; case GL_TEXTURE_CUBE_MAP: for (i = 0; i < 6; i++) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalformat, width, height, 0, format, type, NULL); } break; case GL_TEXTURE_CUBE_MAP_ARRAY: /* cube map arrays also use TexImage3D buth depth * needs to be a multiple of six */ depth = 6; /* fall through */ case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_3D: glTexImage3D(target, 0, internalformat, width, height, depth, 0, format, type, NULL); break; case GL_TEXTURE_2D_MULTISAMPLE: glTexImage2DMultisample(target, 1, internalformat, width, height, GL_FALSE); break; case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: glTexImage3DMultisample(target, 1, internalformat, width, height, depth, GL_FALSE); break; case GL_TEXTURE_BUFFER: glGenBuffers(1, &buffer); glBindBuffer(GL_TEXTURE_BUFFER, buffer); glTexBuffer(GL_TEXTURE_BUFFER, internalformat, buffer); break; default: result = false; fprintf(stderr, "\tError: %s is not a texture target\n", piglit_get_gl_enum_name(target)); } if (!piglit_check_gl_error(GL_NO_ERROR)) result = false; if (!result) { glDeleteTextures(1, &tex); glDeleteBuffers(1, &buffer); } else { *tex_out = tex; *buffer_out = buffer; } return result; }
static enum piglit_result exec_test(struct test_info *info, int sample_count) { GLuint fb, tex, rb; GLint result; struct attachment_info *att; GLint maxColorSamples, maxDepthSamples; glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxColorSamples); glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &maxDepthSamples); glGenFramebuffers(1, &fb); glBindFramebuffer(GL_FRAMEBUFFER, fb); printf("Testing fbo completeness for config '%s'\n", info->name); for (att=info->attachments; att->target; att++) { int attachment_sample_count = att->multisample ? sample_count : 0; printf(" Att target=%s att=%s samples=%d dims=%d,%d,%d fixed=%d\n", piglit_get_gl_enum_name(att->target), piglit_get_gl_enum_name(att->attachment), attachment_sample_count, SURFACE_WIDTH, SURFACE_HEIGHT, att->target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY ? SURFACE_DEPTH : 1, att->fixedsamplelocations); switch (att->target) { case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: if (att->attachment == GL_DEPTH_ATTACHMENT && sample_count > maxDepthSamples) return PIGLIT_SKIP; if ((att->attachment == GL_COLOR_ATTACHMENT0 || att->attachment == GL_COLOR_ATTACHMENT1) && sample_count > maxColorSamples) return PIGLIT_SKIP; } switch (att->target) { case GL_TEXTURE_2D_MULTISAMPLE: glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, attachment_sample_count, choose_format(att), SURFACE_WIDTH, SURFACE_HEIGHT, att->fixedsamplelocations); if (!piglit_check_gl_error(GL_NO_ERROR)) return PIGLIT_FAIL; glFramebufferTexture2D(GL_FRAMEBUFFER, att->attachment, att->target, tex, 0); break; case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, tex); glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, attachment_sample_count, choose_format(att), SURFACE_WIDTH, SURFACE_HEIGHT, SURFACE_DEPTH, att->fixedsamplelocations); if (!piglit_check_gl_error(GL_NO_ERROR)) return PIGLIT_FAIL; glFramebufferTextureLayer(GL_FRAMEBUFFER, att->attachment, tex, 0, att->layer); break; case GL_RENDERBUFFER: /* RENDERBUFFER has fixedsamplelocations implicitly */ assert(att->fixedsamplelocations); glGenRenderbuffers(1, &rb); glBindRenderbuffer(GL_RENDERBUFFER, rb); if (att->multisample) { glRenderbufferStorageMultisample(GL_RENDERBUFFER, attachment_sample_count, choose_format(att), SURFACE_WIDTH, SURFACE_HEIGHT); } else { /* non-MSAA renderbuffer */ glRenderbufferStorage(GL_RENDERBUFFER, choose_format(att), SURFACE_WIDTH, SURFACE_HEIGHT); } glFramebufferRenderbuffer(GL_FRAMEBUFFER, att->attachment, att->target, rb); if (!piglit_check_gl_error(GL_NO_ERROR)) return PIGLIT_FAIL; break; default: assert(!"Unsupported target"); } } result = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (result != info->expected) { printf("glCheckFramebufferStatus: expected %s, got %s\n", piglit_get_gl_enum_name(info->expected), piglit_get_gl_enum_name(result)); return PIGLIT_FAIL; } if (result == GL_FRAMEBUFFER_COMPLETE && info->attachments->multisample) return check_sample_positions(sample_count); return PIGLIT_PASS; }