Home | History | Annotate | Download | only in Main
      1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //    http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "FrameBufferX11.hpp"
     16 
     17 #include "libX11.hpp"
     18 
     19 #include <sys/ipc.h>
     20 #include <sys/shm.h>
     21 #include <string.h>
     22 #include <assert.h>
     23 
     24 namespace sw
     25 {
     26 	static int (*PreviousXErrorHandler)(Display *display, XErrorEvent *event) = 0;
     27 	static bool shmBadAccess = false;
     28 
     29 	// Catches BadAcces errors so we can fall back to not using MIT-SHM
     30 	static int XShmErrorHandler(Display *display, XErrorEvent *event)
     31 	{
     32 		if(event->error_code == BadAccess)
     33 		{
     34 			shmBadAccess = true;
     35 			return 0;
     36 		}
     37 		else
     38 		{
     39 			return PreviousXErrorHandler(display, event);
     40 		}
     41 	}
     42 
     43 	FrameBufferX11::FrameBufferX11(Display *display, Window window, int width, int height) : FrameBuffer(width, height, false, false), ownX11(!display), x_display(display), x_window(window)
     44 	{
     45 		if(!x_display)
     46 		{
     47 			x_display = libX11->XOpenDisplay(0);
     48 		}
     49 
     50 		int screen = DefaultScreen(x_display);
     51 		x_gc = libX11->XDefaultGC(x_display, screen);
     52 		int depth = libX11->XDefaultDepth(x_display, screen);
     53 
     54 		Status status = libX11->XMatchVisualInfo(x_display, screen, 32, TrueColor, &x_visual);
     55 		bool match = (status != 0 && x_visual.blue_mask == 0xFF);   // Prefer X8R8G8B8
     56 		Visual *visual = match ? x_visual.visual : libX11->XDefaultVisual(x_display, screen);
     57 
     58 		mit_shm = (libX11->XShmQueryExtension && libX11->XShmQueryExtension(x_display) == True);
     59 
     60 		if(mit_shm)
     61 		{
     62 			x_image = libX11->XShmCreateImage(x_display, visual, depth, ZPixmap, 0, &shminfo, width, height);
     63 
     64 			shminfo.shmid = shmget(IPC_PRIVATE, x_image->bytes_per_line * x_image->height, IPC_CREAT | SHM_R | SHM_W);
     65 			shminfo.shmaddr = x_image->data = buffer = (char*)shmat(shminfo.shmid, 0, 0);
     66 			shminfo.readOnly = False;
     67 
     68 			PreviousXErrorHandler = libX11->XSetErrorHandler(XShmErrorHandler);
     69 			libX11->XShmAttach(x_display, &shminfo);   // May produce a BadAccess error
     70 			libX11->XSync(x_display, False);
     71 			libX11->XSetErrorHandler(PreviousXErrorHandler);
     72 
     73 			if(shmBadAccess)
     74 			{
     75 				mit_shm = false;
     76 
     77 				XDestroyImage(x_image);
     78 				shmdt(shminfo.shmaddr);
     79 				shmctl(shminfo.shmid, IPC_RMID, 0);
     80 
     81 				shmBadAccess = false;
     82 			}
     83 		}
     84 
     85 		if(!mit_shm)
     86 		{
     87 			buffer = new char[width * height * 4];
     88 			x_image = libX11->XCreateImage(x_display, visual, depth, ZPixmap, 0, buffer, width, height, 32, width * 4);
     89 		}
     90 	}
     91 
     92 	FrameBufferX11::~FrameBufferX11()
     93 	{
     94 		if(!mit_shm)
     95 		{
     96 			x_image->data = 0;
     97 			XDestroyImage(x_image);
     98 
     99 			delete[] buffer;
    100 			buffer = 0;
    101 		}
    102 		else
    103 		{
    104 			libX11->XShmDetach(x_display, &shminfo);
    105 			XDestroyImage(x_image);
    106 			shmdt(shminfo.shmaddr);
    107 			shmctl(shminfo.shmid, IPC_RMID, 0);
    108 		}
    109 
    110 		if(ownX11)
    111 		{
    112 			libX11->XCloseDisplay(x_display);
    113 		}
    114 	}
    115 
    116 	void *FrameBufferX11::lock()
    117 	{
    118 		stride = x_image->bytes_per_line;
    119 		locked = buffer;
    120 
    121 		return locked;
    122 	}
    123 
    124 	void FrameBufferX11::unlock()
    125 	{
    126 		locked = nullptr;
    127 	}
    128 
    129 	void FrameBufferX11::blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride)
    130 	{
    131 		copy(source, sourceFormat, sourceStride);
    132 
    133 		if(!mit_shm)
    134 		{
    135 			libX11->XPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height);
    136 		}
    137 		else
    138 		{
    139 			libX11->XShmPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height, False);
    140 		}
    141 
    142 		libX11->XSync(x_display, False);
    143 	}
    144 }
    145 
    146 NO_SANITIZE_FUNCTION sw::FrameBuffer *createFrameBuffer(void *display, Window window, int width, int height)
    147 {
    148 	return new sw::FrameBufferX11((::Display*)display, window, width, height);
    149 }
    150