1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 29/** 30 * Scene queue. We'll use two queues. One contains "full" scenes which 31 * are produced by the "setup" code. The other contains "empty" scenes 32 * which are produced by the "rast" code when it finishes rendering a scene. 33 */ 34 35#include "os/os_thread.h" 36#include "util/u_memory.h" 37#include "lp_scene_queue.h" 38#include "util/u_math.h" 39#include "lp_setup_context.h" 40 41 42#define SCENE_QUEUE_SIZE MAX_SCENES 43 44 45 46/** 47 * A queue of scenes 48 */ 49struct lp_scene_queue 50{ 51 struct lp_scene *scenes[SCENE_QUEUE_SIZE]; 52 53 mtx_t mutex; 54 cnd_t change; 55 56 /* These values wrap around, so that head == tail means empty. When used 57 * to index the array, we use them modulo the queue size. This scheme 58 * works because the queue size is a power of two. 59 */ 60 unsigned head; 61 unsigned tail; 62}; 63 64 65 66/** Allocate a new scene queue */ 67struct lp_scene_queue * 68lp_scene_queue_create(void) 69{ 70 /* Circular queue behavior depends on size being a power of two. */ 71 STATIC_ASSERT(SCENE_QUEUE_SIZE > 0); 72 STATIC_ASSERT((SCENE_QUEUE_SIZE & (SCENE_QUEUE_SIZE - 1)) == 0); 73 74 struct lp_scene_queue *queue = CALLOC_STRUCT(lp_scene_queue); 75 76 if (!queue) 77 return NULL; 78 79 (void) mtx_init(&queue->mutex, mtx_plain); 80 cnd_init(&queue->change); 81 82 return queue; 83} 84 85 86/** Delete a scene queue */ 87void 88lp_scene_queue_destroy(struct lp_scene_queue *queue) 89{ 90 cnd_destroy(&queue->change); 91 mtx_destroy(&queue->mutex); 92 FREE(queue); 93} 94 95 96/** Remove first lp_scene from head of queue */ 97struct lp_scene * 98lp_scene_dequeue(struct lp_scene_queue *queue, boolean wait) 99{ 100 mtx_lock(&queue->mutex); 101 102 if (wait) { 103 /* Wait for queue to be not empty. */ 104 while (queue->head == queue->tail) 105 cnd_wait(&queue->change, &queue->mutex); 106 } else { 107 if (queue->head == queue->tail) { 108 mtx_unlock(&queue->mutex); 109 return NULL; 110 } 111 } 112 113 struct lp_scene *scene = queue->scenes[queue->head++ % SCENE_QUEUE_SIZE]; 114 115 cnd_signal(&queue->change); 116 mtx_unlock(&queue->mutex); 117 118 return scene; 119} 120 121 122/** Add an lp_scene to tail of queue */ 123void 124lp_scene_enqueue(struct lp_scene_queue *queue, struct lp_scene *scene) 125{ 126 mtx_lock(&queue->mutex); 127 128 /* Wait for free space. */ 129 while (queue->tail - queue->head >= SCENE_QUEUE_SIZE) 130 cnd_wait(&queue->change, &queue->mutex); 131 132 queue->scenes[queue->tail++ % SCENE_QUEUE_SIZE] = scene; 133 134 cnd_signal(&queue->change); 135 mtx_unlock(&queue->mutex); 136} 137