A basic graphics package for the LPC4088 Display Module.

Dependents:   lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI lpc4088_displaymodule_fs_aid ... more

Fork of DMBasicGUI by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Renderer.cpp Source File

Renderer.cpp

00001 /*
00002  *  Copyright 2014 Embedded Artists AB
00003  *
00004  *  Licensed under the Apache License, Version 2.0 (the "License");
00005  *  you may not use this file except in compliance with the License.
00006  *  You may obtain a copy of the License at
00007  *
00008  *    http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  *  Unless required by applicable law or agreed to in writing, software
00011  *  distributed under the License is distributed on an "AS IS" BASIS,
00012  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *  See the License for the specific language governing permissions and
00014  *  limitations under the License.
00015  */
00016  
00017 #include "mbed.h"
00018 #include "Renderer.h"
00019 #include "DMBoard.h"
00020 
00021 /******************************************************************************
00022  * Defines and typedefs
00023  *****************************************************************************/
00024 
00025 #if !defined(MIN)
00026   #define MIN(__a, __b)  (((__a)<(__b))?(__a):(__b))
00027 #endif
00028 
00029 /******************************************************************************
00030  * Public functions
00031  *****************************************************************************/
00032 
00033 Renderer::Renderer()
00034 {
00035   memset(layers, 0, sizeof(layerinfo_t)*MaxNumLayers);
00036   for (int i = 0; i < MaxNumLayers; i++) {
00037     layers[i].used = false;
00038     order[i] = NULL;
00039   }
00040 
00041   numRegisteredLayers = 0;
00042   activeBackBuffer = 0;
00043   display = DMBoard::instance().display();
00044 
00045   this->screenWidth = display->width();
00046   this->screenHeight = display->height();
00047   this->screenPixels = this->screenWidth * this->screenHeight;
00048 
00049   // Assume screen->bpp == Bpp_16
00050   this->screenBytes = display->bytesPerPixel() * this->screenPixels;
00051 
00052   ImageBackBuffer[0] = (image_t)display->allocateFramebuffer();
00053   ImageBackBuffer[1] = (image_t)display->allocateFramebuffer();
00054   if ((ImageBackBuffer[0] == NULL) || (ImageBackBuffer[1] == NULL)) {
00055     printf("Failed to allocate buffer(s) for Renderer. Halting...\n");
00056     while(1) {
00057       ;
00058     }
00059   }
00060   memset(ImageBackBuffer[0], 0xff, screenBytes);
00061   memset(ImageBackBuffer[1], 0xff, screenBytes);
00062 }
00063 
00064 Renderer::~Renderer()
00065 {
00066   free(ImageBackBuffer[0]);
00067   free(ImageBackBuffer[1]);
00068   for (int i = 0; i < MaxNumLayers; i++) {
00069     if (layers[i].used) {
00070       free(layers[i].tmp);
00071       delete(layers[i].lock);
00072     }
00073   }
00074 }
00075 
00076 uint32_t Renderer::registerUser(int layer, int xoff, int yoff, int width, int height)
00077 {
00078   setupMutex.lock();
00079   if (numRegisteredLayers < MaxNumLayers) {
00080     for (int i = 0; i < MaxNumLayers; i++) {
00081       if (!layers[i].used) {
00082         // found a spot
00083         layers[i].used = true;
00084         layers[i].x0 = xoff;
00085         layers[i].y0 = yoff;
00086         layers[i].x1 = MIN(xoff+width, screenWidth);
00087         layers[i].y1 = MIN(yoff+height, screenHeight);
00088         layers[i].width = width;
00089         layers[i].clippedHeight = layers[i].y1 - layers[i].y0;
00090         layers[i].zorder = layer;
00091         layers[i].signalId = 1;//(1<<i);
00092         layers[i].lock = new Mutex();
00093         layers[i].newData = NULL;
00094         layers[i].activeData = NULL;
00095         layers[i].fullscreen = false;
00096         if ((xoff == 0) && (yoff == 0) && (width == screenWidth) && (height == screenHeight)) {
00097           layers[i].fullscreen = true;
00098         }
00099 
00100         layers[i].tmp = (uint16_t*)malloc(width*layers[i].clippedHeight*2);
00101         if (layers[i].tmp != NULL) {
00102           memset(layers[i].tmp, 0, width*layers[i].clippedHeight*2);
00103         }
00104 
00105 
00106         // sort the order
00107         for (int j = 0; j < MaxNumLayers; j++) {
00108           if (order[j] == NULL) {
00109             // no more layers so add the new one to the top
00110             order[j] = &(layers[i]);
00111             break;
00112           }
00113           if (order[j]->zorder > layer) {
00114             // should insert the new layer here
00115             for (int k = numRegisteredLayers; k > j; k--) {
00116               order[k] = order[k-1];
00117             }
00118             order[j] = &(layers[i]);
00119             break;
00120           }
00121         }
00122 
00123         // Cause a repaint of all layers. It does not have to be immediate
00124         // as for unregisterUser() - it is enough that it is done next time.
00125         order[0]->activeData = NULL;
00126 
00127         numRegisteredLayers++;
00128 
00129         setupMutex.unlock();
00130         return (uint32_t)(&(layers[i]));
00131       }
00132     }
00133   }
00134   setupMutex.unlock();
00135   return 0;
00136 }
00137 
00138 uint32_t Renderer::registerFullscreenUser(int layer)
00139 {
00140   return registerUser(layer, 0, 0, screenWidth, screenHeight);
00141 }
00142 
00143 void Renderer::unregisterUser(uint32_t handle)
00144 {
00145   setupMutex.lock();
00146   if (handle != 0) {
00147     layerinfo_t* layer = (layerinfo_t*)handle;
00148     for (int i = 0; i < MaxNumLayers; i++) {
00149       if (order[i] == layer) {
00150         layer->used = false;
00151         free(layer->tmp);
00152         delete layer->lock;
00153 
00154         // move all layers "down" one step
00155         for (int j = i+1; j<numRegisteredLayers; j++) {
00156           order[j-1] = order[j];
00157         }
00158         order[numRegisteredLayers-1] = NULL;
00159         numRegisteredLayers--;
00160 
00161         // cause a repaint
00162         if (order[0] != NULL) {
00163           order[0]->activeData = NULL;
00164 
00165           // Very important that the signal is not sent while the lock is held
00166           // as it will cause the renderer thread be able to take it also
00167           setupMutex.unlock();
00168           osSignalSet(threadId, layer->signalId);
00169           return;
00170         } else {
00171           // no longer anything to show, clear back buffers
00172           memset(ImageBackBuffer[0], 0xff, screenBytes);
00173           memset(ImageBackBuffer[1], 0xff, screenBytes);
00174         }
00175 
00176         break;
00177       }
00178     }
00179   }
00180   setupMutex.unlock();
00181 }
00182 
00183 void Renderer::setFramebuffer(uint32_t handle, const uint16_t* data)
00184 {
00185   layerinfo_t* layer = (layerinfo_t*)handle;
00186 
00187   // make sure that the render thread is not using the data when
00188   // we change it
00189   layer->lock->lock();
00190   layer->newData = data;
00191   layer->activeData = NULL;
00192   layer->lock->unlock();
00193 
00194   // notify the renderer that there is new data for our layer
00195   osSignalSet(threadId, layer->signalId);
00196 }
00197 
00198 void Renderer::render()
00199 {
00200   //save this thread's ID so that it may be signalled from 
00201   //unregisterUser() and setFramebuffer()
00202   threadId = ThisThread::get_id();
00203     
00204   int mask = 1;//(1<<MaxNumLayers) - 1;
00205   while(true)
00206   {
00207     /*osEvent ev =*/ ThisThread::flags_wait_any(mask);
00208     /*if (ev.status == osEventSignal) {*/
00209       setupMutex.lock();
00210       for (int i = 0; i < numRegisteredLayers; i++) {
00211         if (order[i]->activeData != order[i]->newData) {
00212         //if (order[i]->signalId & ev.value.signals) {
00213 
00214           int n = (activeBackBuffer + 1) & 1;
00215 
00216 //          if (i == 0) {
00217 //            // TEMPORARY
00218 //            board->setFrameBuffer((uint32_t)ImageBackBuffer[n]);
00219 //            if (order[i]->activeData != NULL && order[i]->newData != NULL) {
00220 //              for (int y = 0; y < order[i]->clippedHeight; y++) {
00221 //                for (int x = 0; x < order[i]->width; x++) {
00222 //                  if (order[i]->activeData[y*order[i]->width+x] != order[i]->newData[y*order[i]->width+x]) {
00223 //                    printf("Difference in x,y {%d,%d} active is 0x%04x, new is 0x%04x\n", x, y,
00224 //                           order[i]->activeData[y*order[i]->width+x], order[i]->newData[y*order[i]->width+x]);
00225 //                  }
00226 //                }
00227 //              }
00228 //            }
00229 //          }
00230 
00231           // Layer i have new data
00232           // redraw this layer and all on top of it
00233           for (int j = i; j < numRegisteredLayers; j++) {
00234             layerinfo_t* layer = order[j];
00235             layer->lock->lock();
00236             layer->activeData = layer->newData;
00237             memcpy(layer->tmp, layer->newData, layer->width*layer->clippedHeight*2);
00238             layer->lock->unlock();
00239             if (layer->activeData != NULL) {
00240               if (layer->fullscreen) {
00241                 memcpy(ImageBackBuffer[n], layer->tmp, screenBytes);
00242               } else {
00243                 for (int y = 0; y < layer->clippedHeight; y++) {
00244                   memcpy(ImageBackBuffer[n] + ((y + layer->y0) * screenWidth) + layer->x0,
00245                          layer->tmp + (y * layer->width),
00246                          (layer->x1 - layer->x0) * 2);
00247                 }
00248               }
00249             }
00250           }
00251 
00252           //board->setFrameBuffer((uint32_t)ImageBackBuffer[n]);
00253           display->setFramebuffer(ImageBackBuffer[n]);
00254           if (i == (numRegisteredLayers - 1)) {
00255             // only top layer changed, no need to copy entire back buffer
00256           } else {
00257             // more layers exist on top so the back buffer must be updated
00258             memcpy(ImageBackBuffer[activeBackBuffer], ImageBackBuffer[n], screenBytes);
00259           }
00260           activeBackBuffer = n;
00261           break;
00262         }
00263       }
00264       setupMutex.unlock();
00265     /*}*/
00266   }
00267 }