1/*
2 * Copyright 2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *    Alexander von Gluck, kallisti5@unixzen.com
7 */
8
9
10#include "ringqueue.h"
11
12#include <stdlib.h>
13#include <string.h>
14
15
16#define TRACE_RENDER_QUEUE
17#ifdef TRACE_RENDER_QUEUE
18extern "C" void _sPrintf(const char* format, ...);
19#   define TRACE(x...) _sPrintf("radeon_hd: " x)
20#else
21#   define TRACE(x...) ;
22#endif
23
24#define ERROR(x...) _sPrintf("radeon_hd: " x)
25
26
27static const char* queueName[RADEON_QUEUE_MAX] = {
28    "GFX",
29    "CP1",
30    "CP2"
31};
32
33
34int
35compute_order(unsigned long size)
36{
37	int	order;
38	unsigned long tmp;
39	for (order = 0, tmp = size; tmp >>= 1; ++order);
40
41	if (size & ~(1 << order))
42		++order;
43
44	return order;
45}
46
47
48RingQueue::RingQueue(size_t sizeBytes, uint32 queueType)
49	:
50	fQueueType(queueType),
51	fReadPtr(0),
52	fWritePtr(0)
53{
54	TRACE("%s: Requested %d bytes for %s RingQueue.\n", __func__, sizeBytes,
55		queueName[fQueueType]);
56
57	size_t renderQueueSize = compute_order(sizeBytes / 8);
58	fSize = (1 << (renderQueueSize + 1)) * 4;
59	fWriteBytesAvail = fSize;
60	fAlignMask = 16 - 1;
61
62	TRACE("%s: Allocating %d bytes for %s RingQueue.\n", __func__, fSize,
63		queueName[fQueueType]);
64
65	// Allocate buffer memory
66	fData = (unsigned char*)malloc(fSize);
67	// Clear buffer
68	memset(fData, 0, fSize);
69}
70
71
72RingQueue::~RingQueue()
73{
74	TRACE("%s: Closing %s RingQueue.\n", __func__, queueName[fQueueType]);
75	free(fData);
76}
77
78
79status_t
80RingQueue::Empty()
81{
82	TRACE("%s: Clearing %s RingQueue\n", __func__, queueName[fQueueType]);
83	// Clear buffer
84	memset(fData, 0, fSize);
85
86	// Reset counters
87	fReadPtr = 0;
88	fWritePtr = 0;
89	fWriteBytesAvail = fSize;
90	return B_OK;
91}
92
93
94size_t
95RingQueue::Read(unsigned char* dataPtr, size_t bytes)
96{
97	// If there is no data or nothing to read, return 0 bytes
98	if (dataPtr == 0 || bytes <= 0 || fWriteBytesAvail == fSize)
99		return 0;
100
101	size_t readBytesAvail = fSize - fWriteBytesAvail;
102
103	// Set a high threshold of total available bytes available.
104	if (bytes > readBytesAvail)
105		bytes = readBytesAvail;
106
107	// Keep track of position and pull needed data
108	if (bytes > fSize - fReadPtr) {
109		size_t len = fSize - fReadPtr;
110		memcpy(dataPtr, fData + fReadPtr, len);
111		memcpy(dataPtr + len, fData, bytes - len);
112	} else {
113		memcpy(dataPtr, fData + fReadPtr, bytes);
114	}
115
116	fReadPtr = (fReadPtr + bytes) % fSize;
117	fWriteBytesAvail += bytes;
118
119	return bytes;
120}
121
122
123size_t
124RingQueue::Write(unsigned char* dataPtr, size_t bytes)
125{
126	// If there is no data, or no room available, 0 bytes written.
127	if (dataPtr == 0 || bytes <= 0 || fWriteBytesAvail == 0)
128		return 0;
129
130	// Set a high threshold of the number of bytes available.
131	if (bytes > fWriteBytesAvail)
132		bytes = fWriteBytesAvail;
133
134	// Keep track of position and push needed data
135	if (bytes > fSize - fWritePtr) {
136		size_t len = fSize - fWritePtr;
137		memcpy(fData + fWritePtr, dataPtr, len);
138		memcpy(fData, dataPtr + len, bytes - len);
139	} else
140		memcpy(fData + fWritePtr, dataPtr, bytes);
141
142	fWritePtr = (fWritePtr + bytes) % fSize;
143	fWriteBytesAvail -= bytes;
144
145	return bytes;
146}
147