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		if (size & ~(1 << order))
41			++order;
42		return order;
43}
44
45
46RingQueue::RingQueue(size_t sizeBytes, uint32 queueType)
47	:
48	fQueueType(queueType),
49	fReadPtr(0),
50	fWritePtr(0)
51{
52	TRACE("%s: Requested %d bytes for %s RingQueue.\n", __func__, sizeBytes,
53		queueName[fQueueType]);
54
55	size_t renderQueueSize = compute_order(sizeBytes / 8);
56	fSize = (1 << (renderQueueSize + 1)) * 4;
57	fWriteBytesAvail = fSize;
58	fAlignMask = 16 - 1;
59
60	TRACE("%s: Allocating %d bytes for %s RingQueue.\n", __func__, fSize,
61		queueName[fQueueType]);
62
63	// Allocate buffer memory
64	fData = (unsigned char*)malloc(fSize);
65	// Clear buffer
66	memset(fData, 0, fSize);
67}
68
69
70RingQueue::~RingQueue()
71{
72	TRACE("%s: Closing %s RingQueue.\n", __func__, queueName[fQueueType]);
73	free(fData);
74}
75
76
77status_t
78RingQueue::Empty()
79{
80	TRACE("%s: Clearing %s RingQueue\n", __func__, queueName[fQueueType]);
81	// Clear buffer
82	memset(fData, 0, fSize);
83
84	// Reset counters
85	fReadPtr = 0;
86	fWritePtr = 0;
87	fWriteBytesAvail = fSize;
88	return B_OK;
89}
90
91
92size_t
93RingQueue::Read(unsigned char* dataPtr, size_t bytes)
94{
95	// If there is no data or nothing to read, return 0 bytes
96	if (dataPtr == 0 || bytes <= 0 || fWriteBytesAvail == fSize)
97		return 0;
98
99	size_t readBytesAvail = fSize - fWriteBytesAvail;
100
101	// Set a high threshold of total available bytes available.
102	if (bytes > readBytesAvail)
103		bytes = readBytesAvail;
104
105	// Keep track of position and pull needed data
106	if (bytes > fSize - fReadPtr) {
107		size_t len = fSize - fReadPtr;
108		memcpy(dataPtr, fData + fReadPtr, len);
109		memcpy(dataPtr + len, fData, bytes - len);
110	} else {
111		memcpy(dataPtr, fData + fReadPtr, bytes);
112	}
113
114	fReadPtr = (fReadPtr + bytes) % fSize;
115	fWriteBytesAvail += bytes;
116
117	return bytes;
118}
119
120
121size_t
122RingQueue::Write(unsigned char* dataPtr, size_t bytes)
123{
124	// If there is no data, or no room available, 0 bytes written.
125	if (dataPtr == 0 || bytes <= 0 || fWriteBytesAvail == 0)
126		return 0;
127
128	// Set a high threshold of the number of bytes available.
129	if (bytes > fWriteBytesAvail)
130		bytes = fWriteBytesAvail;
131
132	// Keep track of position and push needed data
133	if (bytes > fSize - fWritePtr) {
134		size_t len = fSize - fWritePtr;
135		memcpy(fData + fWritePtr, dataPtr, len);
136		memcpy(fData, dataPtr + len, bytes - len);
137	} else
138		memcpy(fData + fWritePtr, dataPtr, bytes);
139
140	fWritePtr = (fWritePtr + bytes) % fSize;
141	fWriteBytesAvail -= bytes;
142
143	return bytes;
144}
145