From: "Zhigang Gong" <zhigang.gong@linux.intel.com>
To: 'Chris Wilson' <chris@chris-wilson.co.uk>
Cc: intel-gfx@lists.freedesktop.org
Subject: Re: [PATCH] uxa/glamor: Enable the rest glamor rendering functions.
Date: Wed, 14 Dec 2011 12:08:30 +0800 [thread overview]
Message-ID: <0ef901ccba16$0adcc870$20965950$@linux.intel.com> (raw)
In-Reply-To: <aefc95$2i59vr@orsmga001.jf.intel.com>
[-- Attachment #1: Type: text/plain, Size: 2842 bytes --]
> -----Original Message-----
> From: Chris Wilson [mailto:chris@chris-wilson.co.uk]
> Sent: Wednesday, December 14, 2011 2:45 AM
> To: zhigang.gong@linux.intel.com
> Cc: intel-gfx@lists.freedesktop.org; zhigang.gong@gmail.com;
> zhigang.gong@linux.intel.com
> Subject: Re: [PATCH] uxa/glamor: Enable the rest glamor rendering
> functions.
>
> On Tue, 13 Dec 2011 22:31:41 +0800, zhigang.gong@linux.intel.com
> wrote:
> > From: Zhigang Gong <zhigang.gong@linux.intel.com>
> >
> > This commit enable all the rest glamor rendering functions.
> > Tested with latest glamor master branch, can pass rendercheck.
>
> Hmm, it exposes an issue with keeping a bo cache independent of mesa
> and trying to feed it our own handles:
>
> Region for name 6 already exists but is not compatible
>
> The w/a for this would be:
>
> diff --git a/src/intel_glamor.c b/src/intel_glamor.c index
0cf8ed7..2757fd6
> 100644
> --- a/src/intel_glamor.c
> +++ b/src/intel_glamor.c
> @@ -91,6 +91,7 @@ intel_glamor_create_textured_pixmap(PixmapPtr
> pixmap)
> priv = intel_get_pixmap_private(pixmap);
> if (glamor_egl_create_textured_pixmap(pixmap,
> priv->bo->handle,
> priv->stride)) {
> + drm_intel_bo_disable_reuse(priv->bo);
> priv->pinned = 1;
> return TRUE;
> } else
>
> but that gives up all pretense of maintaining a bo cache.
Yes, I think this impacts the performance. Actually, I noticed this problem
and I
spent some time to track the root cause. If everything is ok, this error
should
not be triggered. Although the same BO maybe reused to create a new pixmap,
the previous pixmap which own this BO should be already destroyed. And the
previous image created with the previous pixmap should be destroyed either.
And then, when we create a new pixmap/image with this BO, MESA should not
find any exist image/region for this BO. But it does happen. I tracked
further into
mesa internal and found that the previous image was not destroyed when we
call eglDestroyImageKHR, as its reference count is decreased to zero. It's
weird
for me. Further tracking shows that the root cause is when I use the
texture(bind to
the image) as a shader's source texture, and call glDrawArrays to perform
the
rendering, the texture's reference count will be increased by 1 before
return
from glDrawArrays. And I failed to find any API to decrease it. Then this
texture
can't be freed when destroy that texture and thus the image's reference
count
will also remain 1 and can't be freed either.
The attached is a simple case to show this bug. It was modified from the
eglkms.c
in mesa-demos.
I did send this issue to mesa-dev. Don't have a solution or explanation so
far. Any
idea?
> -Chris
>
> --
> Chris Wilson, Intel Open Source Technology Centre
[-- Attachment #2: eglkms_mod.c --]
[-- Type: application/octet-stream, Size: 11038 bytes --]
#include <stdlib.h>
#include <stdio.h>
#define EGL_EGLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#include <gbm.h>
#include <GL/gl.h>
#include <GL/glu.h>
#ifndef GLAPIENTRY
#define GLAPIENTRY
#endif
#include <GL/glext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <drm.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#ifdef GL_OES_EGL_image
static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_func;
static PFNEGLCREATEIMAGEKHRPROC glEGLCreateImageKHR_func;
#endif
static const char device_name[] = "/dev/dri/card0";
GLint copy_prog;
static GLint
compile_glsl_prog(GLenum type, const char *source)
{
GLint ok;
GLint prog;
prog = glCreateShader(type);
glShaderSource(prog, 1, (const GLchar **) &source, NULL);
glCompileShader(prog);
glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
info = malloc(size);
glGetShaderInfoLog(prog, size, NULL, info);
fprintf(stderr, "Failed to compile %s: %s\n",
type == GL_FRAGMENT_SHADER ? "FS" : "VS", info);
fprintf(stderr, "Program source:\n%s", source);
}
return prog;
}
static void
link_glsl_prog(GLint prog)
{
GLint ok;
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &ok);
if (!ok) {
GLchar *info;
GLint size;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
info = malloc(size);
glGetProgramInfoLog(prog, size, NULL, info);
fprintf(stderr, "Failed to link: %s\n", info);
fprintf(stderr, "GLSL link failure\n");
}
}
#define VERTEX_POS 0
#define VERTEX_SOURCE 1
static void
init_shader(void)
{
const char *copy_vs =
"attribute vec4 v_position;\n"
"attribute vec4 v_texcoord0;\n"
"varying vec2 source_texture;\n"
"void main()\n"
"{\n"
" gl_Position = v_position;\n"
" source_texture = v_texcoord0.xy;\n" "}\n";
const char *copy_fs =
"varying vec2 source_texture;\n"
"uniform sampler2D sampler;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(sampler, source_texture).rgba;\n"
" } \n" ;
GLint sampler_uniform_location;
GLint fs_prog, vs_prog;
copy_prog = glCreateProgram();
vs_prog = compile_glsl_prog(GL_VERTEX_SHADER, copy_vs);
fs_prog = compile_glsl_prog(GL_FRAGMENT_SHADER, copy_fs);
glAttachShader(copy_prog, vs_prog);
glAttachShader(copy_prog, fs_prog);
glBindAttribLocation(copy_prog, VERTEX_POS, "v_position");
glBindAttribLocation(copy_prog, VERTEX_SOURCE, "v_texcoord0");
link_glsl_prog(copy_prog);
glUseProgram(copy_prog);
sampler_uniform_location = glGetUniformLocation(copy_prog, "sampler");
glUniform1i(sampler_uniform_location, 0);
glUseProgram(0);
}
static GLuint
create_tex_from_img(EGLImageKHR image)
{
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glEGLImageTargetTexture2DOES_func (GL_TEXTURE_2D, image);
glBindTexture(GL_TEXTURE_2D, 0);
return tex;
}
static GLuint
create_fbo_render2tex(GLint tex)
{
GLuint fb;
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tex,
0);
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "framebuffer not complete\n");
exit(1);
}
return fb;
}
static EGLImageKHR
create_image_from_handle(EGLDisplay dpy, EGLContext ctx,
int fd, int handle, int width,
int height, int stride, int bpp)
{
struct drm_gem_flink flink;
EGLImageKHR image;
EGLint attribs[] = {
EGL_WIDTH, 0,
EGL_HEIGHT, 0,
EGL_DRM_BUFFER_STRIDE_MESA, 0,
EGL_DRM_BUFFER_FORMAT_MESA,
EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
EGL_DRM_BUFFER_USE_MESA,
EGL_DRM_BUFFER_USE_SHARE_MESA,
EGL_NONE
};
attribs[1] = width;
attribs[3] = height;
attribs[5] = stride * bpp/8;
flink.handle = handle;
if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0)
return EGL_NO_IMAGE_KHR;
image = glEGLCreateImageKHR_func(dpy , ctx,
EGL_DRM_BUFFER_MESA,
(void *) (uintptr_t)flink.name, attribs);
if (image == EGL_NO_IMAGE_KHR)
return EGL_NO_IMAGE_KHR;
return image;
}
/* use shader to copy tex to current fbo. */
static void
copy_tex(GLint tex)
{
static float vertices[8] = { -1, -1,
1, -1,
1, 1,
-1, 1
};
static float texcoords[8] = { 0, 1,
1, 1,
1, 0,
0, 0
};
glVertexAttribPointer(VERTEX_POS, 2, GL_FLOAT,
GL_FALSE, 2 * sizeof(float),
vertices);
glEnableVertexAttribArray(VERTEX_POS);
glVertexAttribPointer(VERTEX_SOURCE, 2, GL_FLOAT,
GL_FALSE, 2 * sizeof(float),
texcoords);
glEnableVertexAttribArray(VERTEX_SOURCE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glUseProgram(copy_prog);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glUseProgram(0);
glDisableVertexAttribArray(VERTEX_SOURCE);
glDisableVertexAttribArray(VERTEX_POS);
}
int main(int argc, char *argv[])
{
EGLDisplay dpy;
EGLContext ctx;
EGLImageKHR shadow_image, screen_image;
EGLint major, minor;
const char *ver, *extensions;
uint32_t shadow_handle, shadow_stride;
int ret, fd;
struct gbm_device *gbm;
struct gbm_bo *shadow_bo, *screen_bo;
GLuint shadow_tex, screen_tex, screen_fb;
fd = open(device_name, O_RDWR);
if (fd < 0) {
/* Probably permissions error */
fprintf(stderr, "couldn't open %s, skipping\n", device_name);
return -1;
}
gbm = gbm_create_device(fd);
if (gbm == NULL) {
fprintf(stderr, "couldn't create gbm device\n");
ret = -1;
goto close_fd;
}
dpy = eglGetDisplay(gbm);
if (dpy == EGL_NO_DISPLAY) {
fprintf(stderr, "eglGetDisplay() failed\n");
ret = -1;
goto destroy_gbm_device;
}
if (!eglInitialize(dpy, &major, &minor)) {
printf("eglInitialize() failed\n");
ret = -1;
goto egl_terminate;
}
ver = eglQueryString(dpy, EGL_VERSION);
printf("EGL_VERSION = %s\n", ver);
extensions = eglQueryString(dpy, EGL_EXTENSIONS);
if (!strstr(extensions, "EGL_KHR_surfaceless_opengl")) {
printf("No support for EGL_KHR_surfaceless_opengl\n");
ret = -1;
goto egl_terminate;
}
eglBindAPI(EGL_OPENGL_API);
ctx = eglCreateContext(dpy, NULL, EGL_NO_CONTEXT, NULL);
if (ctx == NULL) {
fprintf(stderr, "failed to create context\n");
ret = -1;
goto egl_terminate;
}
if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
fprintf(stderr, "failed to make context current\n");
ret = -1;
goto destroy_context;
}
init_shader();
glEGLImageTargetTexture2DOES_func =
(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
eglGetProcAddress("glEGLImageTargetTexture2DOES");
glEGLCreateImageKHR_func = (PFNEGLCREATEIMAGEKHRPROC)
eglGetProcAddress("eglCreateImageKHR");
shadow_bo = gbm_bo_create(gbm, 1024, 768,
GBM_BO_FORMAT_XRGB8888,
GBM_BO_USE_RENDERING);
screen_bo = gbm_bo_create(gbm, 1024, 768,
GBM_BO_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
if (screen_bo == NULL) {
fprintf(stderr, "failed to create gbm screen bo\n");
ret = -1;
goto unmake_current;
}
shadow_handle = gbm_bo_get_handle(shadow_bo).u32;
shadow_stride = gbm_bo_get_pitch(shadow_bo);
shadow_image = create_image_from_handle(dpy, ctx, fd,
shadow_handle,
1024,
768,
shadow_stride,
32);
screen_image = eglCreateImageKHR(dpy, NULL, EGL_NATIVE_PIXMAP_KHR, screen_bo, NULL);
if (screen_image == EGL_NO_IMAGE_KHR || shadow_image == EGL_NO_IMAGE_KHR) {
fprintf(stderr, "failed to create egl image\n");
ret = -1;
goto destroy_gbm_bo;
}
shadow_tex = create_tex_from_img(shadow_image);
screen_tex = create_tex_from_img(screen_image);
screen_fb = create_fbo_render2tex(screen_tex);
/* Copy shadow texture to screen texture by using shader. */
glBindFramebuffer(GL_FRAMEBUFFER, screen_fb);
copy_tex(shadow_tex);
glFlush();
glDeleteFramebuffers(1, &screen_fb);
glDeleteTextures(1, &shadow_tex);
glDeleteTextures(1, &screen_tex);
eglDestroyImageKHR(dpy, shadow_image);
eglDestroyImageKHR(dpy, screen_image);
/* Now create a smaller image from the same handle. */
shadow_image = create_image_from_handle(dpy, ctx, fd,
shadow_handle,
1024 / 2 ,
768 / 2 ,
shadow_stride/2,
32);
if (shadow_image == EGL_NO_IMAGE_KHR) {
/* As we already destroyed the first shadow image which
created from the same handle, we should be able to
create a smaller image from the same handle again.
This is true, if we don't call into
copy_tex(shadow_tex);
But if we call into copy_tex, then we fail here.
You will get error message from the mesa side as below:
"Region for name 1 already exists but is not compatible "
copy_tex(shadow_tex) is a function to use shadow
texture as a texture source, and access it in a
shader program to render the screen fbo. I traced
into the code, and found that glDrawArray will
implicitly increase the shadow texture's reference count.
And then latter when we delete the texture, the
count will remain 1 rather then zero, and then
it will not decrease the corresponding image region's
reference counter and then when we destroy the shadow image,
the image's reference counter will also be 1 and can't
be freed. Then next time we use the same handle to
create a new image, it will find the previou zombie
image region and find they are not compatible.
simply comment out the glDrawArray can avoid the function
goes here too. Don't know how to fix this problem.
*/
fprintf(stderr, "hit a bug?\n");
} else
eglDestroyImageKHR(dpy, shadow_image);
destroy_gbm_bo:
gbm_bo_destroy(shadow_bo);
gbm_bo_destroy(screen_bo);
unmake_current:
eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
destroy_context:
eglDestroyContext(dpy, ctx);
egl_terminate:
eglTerminate(dpy);
destroy_gbm_device:
gbm_device_destroy(gbm);
close_fd:
close(fd);
return ret;
}
[-- Attachment #3: Type: text/plain, Size: 159 bytes --]
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
next prev parent reply other threads:[~2011-12-14 4:08 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-13 14:31 [PATCH] uxa/glamor: Enable the rest glamor rendering functions zhigang.gong
2011-12-13 18:20 ` Chris Wilson
2011-12-14 3:30 ` Zhigang Gong
2011-12-13 18:44 ` Chris Wilson
2011-12-14 4:08 ` Zhigang Gong [this message]
2011-12-14 11:12 ` Chris Wilson
2011-12-14 11:44 ` Zhigang Gong
2011-12-14 12:08 ` Chris Wilson
2011-12-14 11:54 ` Chris Wilson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='0ef901ccba16$0adcc870$20965950$@linux.intel.com' \
--to=zhigang.gong@linux.intel.com \
--cc=chris@chris-wilson.co.uk \
--cc=intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.