/* * Copyright © 2013 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include #include "piglit-framework-gl/piglit_drm_dma_buf.h" #include "image_common.h" #include "sample_common.h" static const char fs_src[] = "#extension GL_OES_EGL_image_external : require\n" "precision mediump float;\n" "uniform samplerExternalOES sampler;\n" "varying vec2 texcoords;\n" "\n" "void main()\n" "{\n" "gl_FragColor = texture2D(sampler, texcoords);\n" "}\n"; static const char vs_src[] = "attribute vec4 piglit_vertex;\n" "attribute vec4 piglit_texcoords;\n" "varying vec2 texcoords;\n" "\n" "void main()\n" "{\n" " texcoords = piglit_texcoords.xy;\n" " gl_Position = piglit_vertex;\n" "}\n"; enum piglit_result texture_for_egl_image(EGLImageKHR img, GLuint *out_tex) { GLuint tex; GLenum error; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); /* Set the image as level zero */ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)img); error = glGetError(); /** * EGL may not support binding of external textures, this is not an * error. */ if (error == GL_INVALID_OPERATION) return PIGLIT_SKIP; if (error != GL_NO_ERROR) { printf("glEGLImageTargetTexture2DOES() failed: %s 0x%x\n", piglit_get_gl_error_name(error), error); return PIGLIT_FAIL; } glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); *out_tex = tex; return PIGLIT_PASS; } void sample_tex(GLuint tex, unsigned x, unsigned y, unsigned w, unsigned h) { GLuint prog; prog = piglit_build_simple_program(vs_src, fs_src); glUseProgram(prog); glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); glUniform1i(glGetUniformLocation(prog, "sampler"), 0); glViewport(x, y, w, h); piglit_draw_rect_tex(-1, -1, 2, 2, 0, 0, 1, 1); glDeleteProgram(prog); glUseProgram(0); } enum piglit_result egl_image_for_dma_buf_fd(struct piglit_dma_buf *buf, int fd, int fourcc, EGLImageKHR *out_img) { EGLint error; EGLImageKHR img; EGLint attr_packed[] = { EGL_WIDTH, buf->w, EGL_HEIGHT, buf->h, EGL_LINUX_DRM_FOURCC_EXT, fourcc, EGL_DMA_BUF_PLANE0_FD_EXT, fd, EGL_DMA_BUF_PLANE0_OFFSET_EXT, buf->offset[0], EGL_DMA_BUF_PLANE0_PITCH_EXT, buf->stride[0], EGL_NONE }; EGLint attr_nv12[] = { EGL_WIDTH, buf->w, EGL_HEIGHT, buf->h, EGL_LINUX_DRM_FOURCC_EXT, fourcc, EGL_DMA_BUF_PLANE0_FD_EXT, fd, EGL_DMA_BUF_PLANE0_OFFSET_EXT, buf->offset[0], EGL_DMA_BUF_PLANE0_PITCH_EXT, buf->stride[0], EGL_DMA_BUF_PLANE1_FD_EXT, fd, EGL_DMA_BUF_PLANE1_OFFSET_EXT, buf->offset[1], EGL_DMA_BUF_PLANE1_PITCH_EXT, buf->stride[1], EGL_NONE }; EGLint attr_yuv420[] = { EGL_WIDTH, buf->w, EGL_HEIGHT, buf->h, EGL_LINUX_DRM_FOURCC_EXT, fourcc, EGL_DMA_BUF_PLANE0_FD_EXT, fd, EGL_DMA_BUF_PLANE0_OFFSET_EXT, buf->offset[0], EGL_DMA_BUF_PLANE0_PITCH_EXT, buf->stride[0], EGL_DMA_BUF_PLANE1_FD_EXT, fd, EGL_DMA_BUF_PLANE1_OFFSET_EXT, buf->offset[1], EGL_DMA_BUF_PLANE1_PITCH_EXT, buf->stride[1], EGL_DMA_BUF_PLANE2_FD_EXT, fd, EGL_DMA_BUF_PLANE2_OFFSET_EXT, buf->offset[2], EGL_DMA_BUF_PLANE2_PITCH_EXT, buf->stride[2], EGL_NONE }; EGLint *attr; switch (fourcc) { case DRM_FORMAT_NV12: case DRM_FORMAT_P010: case DRM_FORMAT_P012: case DRM_FORMAT_P016: attr = attr_nv12; break; case DRM_FORMAT_YUV420: case DRM_FORMAT_YVU420: attr = attr_yuv420; break; default: attr = attr_packed; break; } img = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, (EGLClientBuffer)0, attr); *out_img = img; error = eglGetError(); /* EGL may not support the format, this is not an error. */ if (!img && error == EGL_BAD_MATCH) return PIGLIT_SKIP; if (error != EGL_SUCCESS) { printf("eglCreateImageKHR() failed: %s 0x%x\n", piglit_get_egl_error_name(error), error); return PIGLIT_FAIL; } if (!img) { fprintf(stderr, "image creation succeeded but returned NULL\n"); return PIGLIT_FAIL; } *out_img = img; return PIGLIT_PASS; } static enum piglit_result sample_buffer(struct piglit_dma_buf *buf, int fourcc) { enum piglit_result res; EGLImageKHR img; GLuint tex; int w = buf->w; int h = buf->h; res = egl_image_for_dma_buf_fd(buf, buf->fd, fourcc, &img); /* Release the creator side of the buffer. */ piglit_destroy_dma_buf(buf); if (!img) { /* Close the descriptor also, EGL does not have ownership */ close(buf->fd); } if (res != PIGLIT_PASS) return res; res = texture_for_egl_image(img, &tex); if (res != PIGLIT_PASS) goto destroy; sample_tex(tex, 0, 0, w, h); destroy: glDeleteTextures(1, &tex); eglDestroyImageKHR(eglGetCurrentDisplay(), img); return res; } enum piglit_result dma_buf_create_and_sample_32bpp(unsigned w, unsigned h, int fourcc, const unsigned char *src) { struct piglit_dma_buf *buf; enum piglit_result res; res = piglit_create_dma_buf(w, h, fourcc, src, &buf); if (res != PIGLIT_PASS) return res; return sample_buffer(buf, fourcc); }