main
intel.c
1/* wld: intel.c
2 *
3 * Copyright (c) 2013, 2014 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "drm-private.h"
25#include "drm.h"
26#include "intel/batch.h"
27#include "intel/blt.h"
28#include "wld-private.h"
29
30#include <i915_drm.h>
31#include <intel_bufmgr.h>
32#include <string.h>
33#include <unistd.h>
34
35struct intel_context {
36 struct wld_context base;
37 drm_intel_bufmgr *bufmgr;
38};
39
40struct intel_renderer {
41 struct wld_renderer base;
42 struct intel_batch batch;
43 struct intel_buffer *target;
44};
45
46struct intel_buffer {
47 struct buffer base;
48 struct wld_exporter exporter;
49 drm_intel_bo *bo;
50};
51
52#include "interface/buffer.h"
53#include "interface/context.h"
54#include "interface/renderer.h"
55#define DRM_DRIVER_NAME intel
56#include "interface/drm.h"
57IMPL(intel_context, wld_context)
58IMPL(intel_renderer, wld_renderer)
59IMPL(intel_buffer, wld_buffer)
60
61static void
62pack_gray_row_to_mono(uint8_t *dst, const uint8_t *src, uint32_t width)
63{
64 uint32_t x, bytes_per_row;
65
66 bytes_per_row = (width + 7) / 8;
67 memset(dst, 0, bytes_per_row);
68
69 for (x = 0; x < width; ++x) {
70 if (src[x] >= 128)
71 dst[x / 8] |= 0x80 >> (x & 7);
72 }
73}
74
75/**** DRM driver ****/
76bool
77driver_device_supported(uint32_t vendor_id, uint32_t device_id)
78{
79 return vendor_id == 0x8086;
80}
81
82struct wld_context *
83driver_create_context(int drm_fd)
84{
85 struct intel_context *context;
86
87 context = malloc(sizeof *context);
88
89 if (!context)
90 goto error0;
91
92 context_initialize(&context->base, &wld_context_impl);
93 context->bufmgr = drm_intel_bufmgr_gem_init(drm_fd, INTEL_BATCH_SIZE);
94
95 if (!context->bufmgr)
96 goto error1;
97
98 return &context->base;
99
100error1:
101 free(context);
102error0:
103 return NULL;
104}
105
106/**** Context ****/
107struct wld_renderer *
108context_create_renderer(struct wld_context *base)
109{
110 struct intel_context *context = intel_context(base);
111 struct intel_renderer *renderer;
112
113 if (!(renderer = malloc(sizeof *renderer)))
114 goto error0;
115
116 if (!(intel_batch_initialize(&renderer->batch, context->bufmgr)))
117 goto error1;
118
119 renderer_initialize(&renderer->base, &wld_renderer_impl);
120
121 return &renderer->base;
122
123error1:
124 free(renderer);
125error0:
126 return NULL;
127}
128
129static bool export(struct wld_exporter *exporter, struct wld_buffer *base,
130 uint32_t type, union wld_object *object)
131{
132 struct intel_buffer *buffer = intel_buffer(base);
133
134 switch (type) {
135 case WLD_DRM_OBJECT_HANDLE:
136 object->u32 = buffer->bo->handle;
137 return true;
138 case WLD_DRM_OBJECT_PRIME_FD:
139 if (drm_intel_bo_gem_export_to_prime(buffer->bo, &object->i) != 0)
140 return false;
141 return true;
142 default:
143 return false;
144 }
145}
146
147static struct buffer *
148new_buffer(uint32_t width, uint32_t height,
149 uint32_t format, uint32_t pitch,
150 drm_intel_bo *bo)
151{
152 struct intel_buffer *buffer;
153
154 if (!(buffer = malloc(sizeof *buffer)))
155 return NULL;
156
157 buffer_initialize(&buffer->base, &wld_buffer_impl,
158 width, height, format, pitch);
159 buffer->bo = bo;
160 buffer->exporter.export = &export;
161 wld_buffer_add_exporter(&buffer->base.base, &buffer->exporter);
162
163 return &buffer->base;
164}
165
166struct buffer *
167context_create_buffer(struct wld_context *base,
168 uint32_t width, uint32_t height,
169 uint32_t format, uint32_t flags)
170{
171 struct intel_context *context = intel_context(base);
172 struct buffer *buffer;
173 drm_intel_bo *bo;
174 uint32_t tiling_mode = width >= 128 && !(flags & WLD_FLAG_CURSOR) ? I915_TILING_X : I915_TILING_NONE;
175 unsigned long pitch;
176
177 bo = drm_intel_bo_alloc_tiled(context->bufmgr, "buffer", width, height, 4,
178 &tiling_mode, &pitch, 0);
179
180 if (!bo)
181 goto error0;
182
183 if (!(buffer = new_buffer(width, height, format, pitch, bo)))
184 goto error1;
185
186 return buffer;
187
188error1:
189 drm_intel_bo_unreference(bo);
190error0:
191 return NULL;
192}
193
194struct buffer *
195context_import_buffer(struct wld_context *base,
196 uint32_t type, union wld_object object,
197 uint32_t width, uint32_t height,
198 uint32_t format, uint32_t pitch)
199{
200 struct intel_context *context = intel_context(base);
201 struct buffer *buffer;
202 drm_intel_bo *bo;
203
204 switch (type) {
205 case WLD_DRM_OBJECT_PRIME_FD: {
206 uint32_t size = width * height * format_bytes_per_pixel(format);
207 bo = drm_intel_bo_gem_create_from_prime(context->bufmgr,
208 object.i, size);
209 break;
210 }
211 default:
212 bo = NULL;
213 };
214
215 if (!bo)
216 goto error0;
217
218 if (!(buffer = new_buffer(width, height, format, pitch, bo)))
219 goto error1;
220
221 return buffer;
222
223error1:
224 drm_intel_bo_unreference(bo);
225error0:
226 return NULL;
227}
228
229void
230context_destroy(struct wld_context *base)
231{
232 struct intel_context *context = intel_context(base);
233
234 drm_intel_bufmgr_destroy(context->bufmgr);
235 free(context);
236}
237
238/**** Renderer ****/
239uint32_t
240renderer_capabilities(struct wld_renderer *renderer, struct buffer *buffer)
241{
242 if (buffer->base.impl == &wld_buffer_impl)
243 return WLD_CAPABILITY_READ | WLD_CAPABILITY_WRITE;
244
245 return 0;
246}
247
248bool
249renderer_set_target(struct wld_renderer *base, struct buffer *buffer)
250{
251 struct intel_renderer *renderer = intel_renderer(base);
252
253 if (buffer && buffer->base.impl != &wld_buffer_impl)
254 return false;
255
256 renderer->target = buffer ? intel_buffer(&buffer->base) : NULL;
257
258 return true;
259}
260
261void
262renderer_fill_rectangle(struct wld_renderer *base, uint32_t color,
263 int32_t x, int32_t y,
264 uint32_t width, uint32_t height)
265{
266 struct intel_renderer *renderer = intel_renderer(base);
267 struct intel_buffer *dst = renderer->target;
268
269 xy_color_blt(&renderer->batch, dst->bo, dst->base.base.pitch,
270 x, y, x + width, y + height, color);
271}
272
273void
274renderer_copy_rectangle(struct wld_renderer *base,
275 struct buffer *buffer_base,
276 int32_t dst_x, int32_t dst_y,
277 int32_t src_x, int32_t src_y,
278 uint32_t width, uint32_t height)
279{
280 struct intel_renderer *renderer = intel_renderer(base);
281
282 if (buffer_base->base.impl != &wld_buffer_impl)
283 return;
284
285 struct intel_buffer *src = intel_buffer(&buffer_base->base),
286 *dst = renderer->target;
287
288 xy_src_copy_blt(&renderer->batch,
289 src->bo, src->base.base.pitch, src_x, src_y,
290 dst->bo, dst->base.base.pitch, dst_x, dst_y, width, height);
291}
292
293void
294renderer_draw_text(struct wld_renderer *base,
295 struct font *font, uint32_t color,
296 int32_t x, int32_t y, const char *text,
297 uint32_t length, struct wld_extents *extents)
298{
299 struct intel_renderer *renderer = intel_renderer(base);
300 struct intel_buffer *dst = renderer->target;
301 int ret;
302 struct glyph *glyph;
303 uint32_t row;
304 FT_UInt glyph_index;
305 uint32_t c;
306 uint8_t immediate[512];
307 uint8_t *byte;
308 int32_t origin_x = x;
309
310 xy_setup_blt(&renderer->batch, true, BLT_RASTER_OPERATION_SRC,
311 0, color, dst->bo, dst->base.base.pitch);
312
313 if (length == -1)
314 length = strlen(text);
315
316 while ((ret = FcUtf8ToUcs4((FcChar8 *)text, &c, length)) > 0 && c != '\0') {
317 text += ret;
318 length -= ret;
319 glyph_index = FT_Get_Char_Index(font->face, c);
320
321 if (!font_ensure_glyph(font, glyph_index))
322 continue;
323
324 glyph = font->glyphs[glyph_index];
325
326 if (glyph->bitmap.width == 0 || glyph->bitmap.rows == 0)
327 goto advance;
328
329 byte = immediate;
330
331 /* XY_TEXT_IMMEDIATE requires a pitch with no extra bytes */
332 for (row = 0; row < glyph->bitmap.rows; ++row) {
333 const uint8_t *src = glyph->bitmap.buffer +
334 (row * glyph->bitmap.pitch);
335 uint32_t bytes_per_row = (glyph->bitmap.width + 7) / 8;
336
337 if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
338 memcpy(byte, src, bytes_per_row);
339 } else {
340 pack_gray_row_to_mono(byte, src, glyph->bitmap.width);
341 }
342 byte += (glyph->bitmap.width + 7) / 8;
343 }
344
345 retry:
346 ret = xy_text_immediate_blt(&renderer->batch, dst->bo,
347 origin_x + glyph->x, y + glyph->y,
348 origin_x + glyph->x + glyph->bitmap.width,
349 y + glyph->y + glyph->bitmap.rows,
350 (byte - immediate + 3) / 4,
351 (uint32_t *)immediate);
352
353 if (ret == INTEL_BATCH_NO_SPACE) {
354 intel_batch_flush(&renderer->batch);
355 xy_setup_blt(&renderer->batch, true, BLT_RASTER_OPERATION_SRC,
356 0, color, dst->bo, dst->base.base.pitch);
357 goto retry;
358 }
359
360 advance:
361 origin_x += glyph->advance;
362 }
363
364 if (extents)
365 extents->advance = origin_x - x;
366}
367
368void
369renderer_flush(struct wld_renderer *base)
370{
371 struct intel_renderer *renderer = intel_renderer(base);
372
373 intel_batch_flush(&renderer->batch);
374}
375
376void
377renderer_destroy(struct wld_renderer *base)
378{
379 struct intel_renderer *renderer = intel_renderer(base);
380
381 intel_batch_finalize(&renderer->batch);
382 free(renderer);
383}
384
385/**** Buffer ****/
386bool
387buffer_map(struct buffer *base)
388{
389 struct intel_buffer *buffer = intel_buffer(&base->base);
390
391 if (drm_intel_gem_bo_map_gtt(buffer->bo) != 0)
392 return false;
393
394 buffer->base.base.map = buffer->bo->virtual;
395
396 return true;
397}
398
399bool
400buffer_unmap(struct buffer *base)
401{
402 struct intel_buffer *buffer = intel_buffer(&base->base);
403
404 if (drm_intel_gem_bo_unmap_gtt(buffer->bo) != 0)
405 return false;
406
407 buffer->base.base.map = NULL;
408
409 return true;
410}
411
412void
413buffer_destroy(struct buffer *base)
414{
415 struct intel_buffer *buffer = intel_buffer(&base->base);
416
417 drm_intel_bo_unreference(buffer->bo);
418 free(buffer);
419}