FrameBufferX11.cpp revision 708c24b3cd03b68aa98b29a9099d6a9ce96eca16
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#include "Common/Timer.hpp" 19 20#include <sys/ipc.h> 21#include <sys/shm.h> 22#include <string.h> 23#include <assert.h> 24 25namespace sw 26{ 27 static int (*PreviousXErrorHandler)(Display *display, XErrorEvent *event) = 0; 28 static bool shmBadAccess = false; 29 30 // Catches BadAcces errors so we can fall back to not using MIT-SHM 31 static int XShmErrorHandler(Display *display, XErrorEvent *event) 32 { 33 if(event->error_code == BadAccess) 34 { 35 shmBadAccess = true; 36 return 0; 37 } 38 else 39 { 40 return PreviousXErrorHandler(display, event); 41 } 42 } 43 44 FrameBufferX11::FrameBufferX11(Display *display, Window window, int width, int height) : FrameBuffer(width, height, false, false), ownX11(!display), x_display(display), x_window(window) 45 { 46 if(!x_display) 47 { 48 x_display = libX11->XOpenDisplay(0); 49 } 50 51 int screen = DefaultScreen(x_display); 52 x_gc = libX11->XDefaultGC(x_display, screen); 53 int depth = libX11->XDefaultDepth(x_display, screen); 54 55 Status status = libX11->XMatchVisualInfo(x_display, screen, 32, TrueColor, &x_visual); 56 bool match = (status != 0 && x_visual.blue_mask == 0xFF); // Prefer X8R8G8B8 57 Visual *visual = match ? x_visual.visual : libX11->XDefaultVisual(x_display, screen); 58 59 mit_shm = (libX11->XShmQueryExtension && libX11->XShmQueryExtension(x_display) == True); 60 61 if(mit_shm) 62 { 63 x_image = libX11->XShmCreateImage(x_display, visual, depth, ZPixmap, 0, &shminfo, width, height); 64 65 shminfo.shmid = shmget(IPC_PRIVATE, x_image->bytes_per_line * x_image->height, IPC_CREAT | SHM_R | SHM_W); 66 shminfo.shmaddr = x_image->data = buffer = (char*)shmat(shminfo.shmid, 0, 0); 67 shminfo.readOnly = False; 68 69 PreviousXErrorHandler = libX11->XSetErrorHandler(XShmErrorHandler); 70 libX11->XShmAttach(x_display, &shminfo); // May produce a BadAccess error 71 libX11->XSync(x_display, False); 72 libX11->XSetErrorHandler(PreviousXErrorHandler); 73 74 if(shmBadAccess) 75 { 76 mit_shm = false; 77 78 XDestroyImage(x_image); 79 shmdt(shminfo.shmaddr); 80 shmctl(shminfo.shmid, IPC_RMID, 0); 81 82 shmBadAccess = false; 83 } 84 } 85 86 if(!mit_shm) 87 { 88 int bytes_per_line = width * 4; 89 int bytes_per_image = height * bytes_per_line; 90 buffer = new char[bytes_per_image]; 91 memset(buffer, 0, bytes_per_image); 92 x_image = libX11->XCreateImage(x_display, visual, depth, ZPixmap, 0, buffer, width, height, 32, bytes_per_line); 93 } 94 } 95 96 FrameBufferX11::~FrameBufferX11() 97 { 98 if(!mit_shm) 99 { 100 x_image->data = 0; 101 XDestroyImage(x_image); 102 103 delete[] buffer; 104 buffer = 0; 105 } 106 else 107 { 108 libX11->XShmDetach(x_display, &shminfo); 109 XDestroyImage(x_image); 110 shmdt(shminfo.shmaddr); 111 shmctl(shminfo.shmid, IPC_RMID, 0); 112 } 113 114 if(ownX11) 115 { 116 libX11->XCloseDisplay(x_display); 117 } 118 } 119 120 void *FrameBufferX11::lock() 121 { 122 stride = x_image->bytes_per_line; 123 locked = buffer; 124 125 return locked; 126 } 127 128 void FrameBufferX11::unlock() 129 { 130 locked = nullptr; 131 } 132 133 void FrameBufferX11::blit(void *source, const Rect *sourceRect, const Rect *destRect, Format sourceFormat, size_t sourceStride) 134 { 135 copy(source, sourceFormat, sourceStride); 136 137 if(!mit_shm) 138 { 139 libX11->XPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height); 140 } 141 else 142 { 143 libX11->XShmPutImage(x_display, x_window, x_gc, x_image, 0, 0, 0, 0, width, height, False); 144 } 145 146 libX11->XSync(x_display, False); 147 148 if(false) // Draw the framerate on screen 149 { 150 static double fpsTime = sw::Timer::seconds(); 151 static int frames = -1; 152 153 double time = sw::Timer::seconds(); 154 double delta = time - fpsTime; 155 frames++; 156 157 static double FPS = 0.0; 158 static double maxFPS = 0.0; 159 160 if(delta > 1.0) 161 { 162 FPS = frames / delta; 163 164 fpsTime = time; 165 frames = 0; 166 167 if(FPS > maxFPS) 168 { 169 maxFPS = FPS; 170 } 171 } 172 173 char string[256]; 174 sprintf(string, "FPS: %.2f (max: %.2f)", FPS, maxFPS); 175 libX11->XDrawString(x_display, x_window, x_gc, 50, 50, string, strlen(string)); 176 } 177 } 178} 179 180NO_SANITIZE_FUNCTION sw::FrameBuffer *createFrameBuffer(void *display, Window window, int width, int height) 181{ 182 return new sw::FrameBufferX11((::Display*)display, window, width, height); 183} 184