All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/7] lib: add igt_wait()
@ 2015-03-25 21:50 Paulo Zanoni
  2015-03-25 21:50 ` [PATCH 2/7] tests/kms_fb_crc: call gem_sync() instead of gem_bo_busy() Paulo Zanoni
                   ` (5 more replies)
  0 siblings, 6 replies; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-25 21:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

Just a little helper for code that needs to wait for a certain
condition to happen. It has the nice advantage that it can survive the
signal helper.

Despite the callers added in this patch, there is another that will go
in a separate patch, and another in a new IGT test file that I plan to
push later.

v2: Check COND again before returning in case we hit the timeout.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 lib/igt_aux.c  | 18 +-----------------
 lib/igt_aux.h  | 43 +++++++++++++++++++++++++++++++++++++++++++
 tests/pm_rpm.c | 28 +++++-----------------------
 3 files changed, 49 insertions(+), 40 deletions(-)

diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index 131ff4b..c98d691 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -556,29 +556,13 @@ enum igt_runtime_pm_status igt_get_runtime_pm_status(void)
  * Waits until for the driver to switch to into the desired runtime PM status,
  * with a 10 second timeout.
  *
- * Some subtests call this function while the signal helper is active, so we
- * can't assume each usleep() call will sleep for 100ms.
- *
  * Returns:
  * True if the desired runtime PM status was attained, false if the operation
  * timed out.
  */
 bool igt_wait_for_pm_status(enum igt_runtime_pm_status status)
 {
-	struct timeval start, end, diff;
-
-	igt_assert(gettimeofday(&start, NULL) == 0);
-	do {
-		if (igt_get_runtime_pm_status() == status)
-			return true;
-
-		usleep(100 * 1000);
-
-		igt_assert(gettimeofday(&end, NULL) == 0);
-		timersub(&end, &start, &diff);
-	} while (diff.tv_sec < 10);
-
-	return false;
+	return igt_wait(igt_get_runtime_pm_status() == status, 10000, 100);
 }
 
 /* Functions with prefix kmstest_ independent of cairo library are pulled out
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
index 0c361f2..3112517 100644
--- a/lib/igt_aux.h
+++ b/lib/igt_aux.h
@@ -30,6 +30,7 @@
 
 #include <intel_bufmgr.h>
 #include <stdbool.h>
+#include <sys/time.h>
 
 extern drm_intel_bo **trash_bos;
 extern int num_trash_bos;
@@ -101,4 +102,46 @@ void intel_require_memory(uint32_t count, uint32_t size, unsigned mode);
 void igt_lock_mem(size_t size);
 void igt_unlock_mem(void);
 
+/**
+ * igt_wait:
+ * @COND: condition to wait
+ * @timeout_ms: timeout in milliseconds
+ * @interval_ms: amount of time we try to sleep between COND checks
+ *
+ * Waits until COND evaluates to true or the timeout passes.
+ *
+ * It is safe to call this macro if the signal helper is active. The only
+ * problem is that the usleep() calls will return early, making us evaluate COND
+ * too often, possibly eating valuable CPU cycles.
+ *
+ * Returns:
+ * True of COND evaluated to true, false otherwise.
+ */
+#define igt_wait(COND, timeout_ms, interval_ms) ({			\
+	struct timeval start_, end_, diff_;				\
+	int elapsed_ms_;						\
+	bool ret_ = false;						\
+									\
+	igt_assert(gettimeofday(&start_, NULL) == 0);			\
+	do {								\
+		if (COND) {						\
+			ret_ = true;					\
+			break;						\
+		}							\
+									\
+		usleep(interval_ms * 1000);				\
+									\
+		igt_assert(gettimeofday(&end_, NULL) == 0);		\
+		timersub(&end_, &start_, &diff_);			\
+									\
+		elapsed_ms_ = diff_.tv_sec * 1000 +			\
+			      diff_.tv_usec / 1000;			\
+	} while (elapsed_ms_ < timeout_ms);				\
+									\
+	if (!ret_ && (COND))						\
+		ret_ = true;						\
+									\
+	ret_;								\
+})
+
 #endif /* IGT_AUX_H */
diff --git a/tests/pm_rpm.c b/tests/pm_rpm.c
index 91df93a..1a93fe8 100644
--- a/tests/pm_rpm.c
+++ b/tests/pm_rpm.c
@@ -153,24 +153,16 @@ static uint64_t get_residency(uint32_t type)
 
 static bool pc8_plus_residency_changed(unsigned int timeout_sec)
 {
-	unsigned int i;
 	uint64_t res_pc8, res_pc9, res_pc10;
-	int to_sleep = 100 * 1000;
 
 	res_pc8 = get_residency(MSR_PC8_RES);
 	res_pc9 = get_residency(MSR_PC9_RES);
 	res_pc10 = get_residency(MSR_PC10_RES);
 
-	for (i = 0; i < timeout_sec * 1000 * 1000; i += to_sleep) {
-		if (res_pc8 != get_residency(MSR_PC8_RES) ||
-		    res_pc9 != get_residency(MSR_PC9_RES) ||
-		    res_pc10 != get_residency(MSR_PC10_RES)) {
-			return true;
-		}
-		usleep(to_sleep);
-	}
-
-	return false;
+	return igt_wait(res_pc8 != get_residency(MSR_PC8_RES) ||
+			res_pc9 != get_residency(MSR_PC9_RES) ||
+			res_pc10 != get_residency(MSR_PC10_RES),
+			timeout_sec * 1000, 100);
 }
 
 static enum pc8_status get_pc8_status(void)
@@ -191,17 +183,7 @@ static enum pc8_status get_pc8_status(void)
 
 static bool wait_for_pc8_status(enum pc8_status status)
 {
-	int i;
-	int hundred_ms = 100 * 1000, ten_s = 10 * 1000 * 1000;
-
-	for (i = 0; i < ten_s; i += hundred_ms) {
-		if (get_pc8_status() == status)
-			return true;
-
-		usleep(hundred_ms);
-	}
-
-	return false;
+	return igt_wait(get_pc8_status() == status, 10000, 100);
 }
 
 static bool wait_for_suspended(void)
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 2/7] tests/kms_fb_crc: call gem_sync() instead of gem_bo_busy()
  2015-03-25 21:50 [PATCH 1/7] lib: add igt_wait() Paulo Zanoni
@ 2015-03-25 21:50 ` Paulo Zanoni
  2015-03-26 10:06   ` Daniel Vetter
  2015-03-25 21:50 ` [PATCH 3/7] tests/kms_fbc_crc: add wait_for_fbc_enabled() Paulo Zanoni
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-25 21:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

The way kms_fbc_crc works is that it does an operation that may
trigger/invalidate/update FBC, then it sleeps for 300ms to wait for
FBC to kick in again, then it calls "igt_assert(fbc_enabled())".

This was causing problems where the BLT test would eventually fail in
the fbc_eanbled() assertion.

With the recent FBC move to front buffer rendering tracking, if we
don't call gem_sync() after submitting render and blt commands, it may
take much more than 300ms for FBC to be reenabled:
i915_gem_execbuffer2() indirectly calls intel_fb_obj_invalidate(),
which disables FBC, and then it is only reenabled when
i915_gem_retire_work_handler() happens and indirectly calls
intel_frontbuffer_flush(). Notice that while FBC is not yet enabled,
the screen contents are correct, so this shouldn't really be a "bug".

The gem_sync() call will make sure the long waits don't happen. With
this, 300ms should be much more than enough: either we wait about 50ms
for FBC to be re-enabled - intel_enable_fbc() uses a delayed work - or
it's instantaneous - on the cases where we just do the nuke.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 tests/kms_fbc_crc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
index 4256fed..b3e6109 100644
--- a/tests/kms_fbc_crc.c
+++ b/tests/kms_fbc_crc.c
@@ -122,7 +122,7 @@ static void fill_blt(data_t *data,
 	intel_batchbuffer_flush(batch);
 	intel_batchbuffer_free(batch);
 
-	gem_bo_busy(data->drm_fd, handle);
+	gem_sync(data->drm_fd, handle);
 }
 
 static void scratch_buf_init(struct igt_buf *buf, drm_intel_bo *bo)
@@ -187,7 +187,7 @@ static void fill_render(data_t *data, uint32_t handle,
 
 	intel_batchbuffer_free(batch);
 
-	gem_bo_busy(data->drm_fd, handle);
+	gem_sync(data->drm_fd, handle);
 }
 
 static bool fbc_enabled(data_t *data)
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 3/7] tests/kms_fbc_crc: add wait_for_fbc_enabled()
  2015-03-25 21:50 [PATCH 1/7] lib: add igt_wait() Paulo Zanoni
  2015-03-25 21:50 ` [PATCH 2/7] tests/kms_fb_crc: call gem_sync() instead of gem_bo_busy() Paulo Zanoni
@ 2015-03-25 21:50 ` Paulo Zanoni
  2015-03-26 10:07   ` Daniel Vetter
  2015-03-25 21:50 ` [PATCH 4/7] tests/kms_fbc_crc: also gem_sync() on exec_nop() Paulo Zanoni
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-25 21:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

The code has a common pattern of "wait 300ms, then check if FBC is
enabled". Most of the time FBC is enabled in either 50ms or 0ms, so
introduce wait_for_fbc_enabled(), which can return much earlier if FBC
is actually enabled before the 300ms timeout.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 tests/kms_fbc_crc.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
index b3e6109..11078e0 100644
--- a/tests/kms_fbc_crc.c
+++ b/tests/kms_fbc_crc.c
@@ -28,6 +28,7 @@
 #include <string.h>
 
 #include "drmtest.h"
+#include "igt_aux.h"
 #include "igt_debugfs.h"
 #include "igt_kms.h"
 #include "intel_chipset.h"
@@ -203,6 +204,11 @@ static bool fbc_enabled(data_t *data)
 	return strstr(str, "FBC enabled") != NULL;
 }
 
+static bool wait_for_fbc_enabled(data_t *data)
+{
+	return igt_wait(fbc_enabled(data), 300, 30);
+}
+
 static void test_crc(data_t *data, enum test_mode mode)
 {
 	uint32_t crtc_id = data->output->config.crtc->crtc_id;
@@ -216,9 +222,8 @@ static void test_crc(data_t *data, enum test_mode mode)
 		handle = data->handle[1];
 		igt_assert(drmModePageFlip(data->drm_fd, crtc_id,
 					   data->fb_id[1], 0, NULL) == 0);
-		usleep(300000);
 
-		igt_assert(fbc_enabled(data));
+		igt_assert(wait_for_fbc_enabled(data));
 	}
 
 	switch (mode) {
@@ -277,9 +282,7 @@ static void test_crc(data_t *data, enum test_mode mode)
 	 * Allow time for FBC to kick in again if it
 	 * got disabled during dirtyfb or page flip.
 	 */
-	usleep(300000);
-
-	igt_assert(fbc_enabled(data));
+	igt_assert(wait_for_fbc_enabled(data));
 
 	igt_pipe_crc_start(pipe_crc);
 	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
@@ -338,9 +341,8 @@ static bool prepare_test(data_t *data, enum test_mode test_mode)
 	/* scanout = fb[1] */
 	igt_plane_set_fb(data->primary, &data->fb[1]);
 	igt_display_commit(display);
-	usleep(300000);
 
-	if (!fbc_enabled(data)) {
+	if (!wait_for_fbc_enabled(data)) {
 		igt_info("FBC not enabled\n");
 
 		igt_plane_set_fb(data->primary, NULL);
@@ -388,9 +390,8 @@ static bool prepare_test(data_t *data, enum test_mode test_mode)
 	/* scanout = fb[0] */
 	igt_plane_set_fb(data->primary, &data->fb[0]);
 	igt_display_commit(display);
-	usleep(300000);
 
-	igt_assert(fbc_enabled(data));
+	igt_assert(wait_for_fbc_enabled(data));
 
 	if (test_mode == TEST_CONTEXT || test_mode == TEST_PAGE_FLIP_AND_CONTEXT) {
 		/*
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 4/7] tests/kms_fbc_crc: also gem_sync() on exec_nop()
  2015-03-25 21:50 [PATCH 1/7] lib: add igt_wait() Paulo Zanoni
  2015-03-25 21:50 ` [PATCH 2/7] tests/kms_fb_crc: call gem_sync() instead of gem_bo_busy() Paulo Zanoni
  2015-03-25 21:50 ` [PATCH 3/7] tests/kms_fbc_crc: add wait_for_fbc_enabled() Paulo Zanoni
@ 2015-03-25 21:50 ` Paulo Zanoni
  2015-03-25 21:50 ` [PATCH 5/7] tests/kms_fbc_crc: use igt_pipe_crc_collect_crc() Paulo Zanoni
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-25 21:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

When we're doing the context subtest, at the end of prepare_test() we
exec a single nop batch on the front buffer, which invalidates FBC.
With the new frontbuffer tracking scheme it may take a while for FBC
to be reenabled, so we end up failing the first fbc_enabled()
assertion inside test_crc().

Other possible implementations:
 - Call gem_sync() at the specific prepare_test() point, not at every
   exec_nop() call.
 - Change the fbc_enabled() assertion to wait_for_fbc_enabled() and
   give it a bigger timeout value.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 tests/kms_fbc_crc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
index 11078e0..d81f4a2 100644
--- a/tests/kms_fbc_crc.c
+++ b/tests/kms_fbc_crc.c
@@ -155,6 +155,8 @@ static void exec_nop(data_t *data, uint32_t handle, drm_intel_context *context)
 
 	intel_batchbuffer_flush_with_context(batch, context);
 	intel_batchbuffer_free(batch);
+
+	gem_sync(data->drm_fd, handle);
 }
 
 static void fill_render(data_t *data, uint32_t handle,
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 5/7] tests/kms_fbc_crc: use igt_pipe_crc_collect_crc()
  2015-03-25 21:50 [PATCH 1/7] lib: add igt_wait() Paulo Zanoni
                   ` (2 preceding siblings ...)
  2015-03-25 21:50 ` [PATCH 4/7] tests/kms_fbc_crc: also gem_sync() on exec_nop() Paulo Zanoni
@ 2015-03-25 21:50 ` Paulo Zanoni
  2015-03-25 21:50 ` [PATCH 6/7] tests/kms_fbc_crc: remove redundant information from data_t Paulo Zanoni
  2015-03-25 21:50 ` [PATCH 7/7] lib: add igt_draw Paulo Zanoni
  5 siblings, 0 replies; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-25 21:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

Instead of its hardcoded implementation.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 tests/kms_fbc_crc.c | 29 +++++++----------------------
 1 file changed, 7 insertions(+), 22 deletions(-)

diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
index d81f4a2..f1888c4 100644
--- a/tests/kms_fbc_crc.c
+++ b/tests/kms_fbc_crc.c
@@ -215,7 +215,7 @@ static void test_crc(data_t *data, enum test_mode mode)
 {
 	uint32_t crtc_id = data->output->config.crtc->crtc_id;
 	igt_pipe_crc_t *pipe_crc = data->pipe_crc;
-	igt_crc_t *crcs = NULL;
+	igt_crc_t crc;
 	uint32_t handle = data->handle[0];
 
 	igt_assert(fbc_enabled(data));
@@ -271,14 +271,11 @@ static void test_crc(data_t *data, enum test_mode mode)
 	igt_wait_for_vblank(data->drm_fd, data->pipe);
 	igt_wait_for_vblank(data->drm_fd, data->pipe);
 
-	igt_pipe_crc_start(pipe_crc);
-	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
-	igt_pipe_crc_stop(pipe_crc);
+	igt_pipe_crc_collect_crc(pipe_crc, &crc);
 	if (mode == TEST_PAGE_FLIP)
-		igt_assert_crc_equal(&crcs[0], &data->ref_crc[1]);
+		igt_assert_crc_equal(&crc, &data->ref_crc[1]);
 	else
 		;/* FIXME: missing reference CRCs */
-	free(crcs);
 
 	/*
 	 * Allow time for FBC to kick in again if it
@@ -286,14 +283,11 @@ static void test_crc(data_t *data, enum test_mode mode)
 	 */
 	igt_assert(wait_for_fbc_enabled(data));
 
-	igt_pipe_crc_start(pipe_crc);
-	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
-	igt_pipe_crc_stop(pipe_crc);
+	igt_pipe_crc_collect_crc(pipe_crc, &crc);
 	if (mode == TEST_PAGE_FLIP)
-		igt_assert_crc_equal(&crcs[0], &data->ref_crc[1]);
+		igt_assert_crc_equal(&crc, &data->ref_crc[1]);
 	else
 		;/* FIXME: missing reference CRCs */
-	free(crcs);
 }
 
 static bool prepare_crtc(data_t *data)
@@ -320,7 +314,6 @@ static bool prepare_test(data_t *data, enum test_mode test_mode)
 	igt_output_t *output = data->output;
 	drmModeModeInfo *mode;
 	igt_pipe_crc_t *pipe_crc;
-	igt_crc_t *crcs = NULL;
 
 	data->primary = igt_output_get_plane(data->output, IGT_PLANE_PRIMARY);
 	mode = igt_output_get_mode(data->output);
@@ -367,11 +360,7 @@ static bool prepare_test(data_t *data, enum test_mode test_mode)
 	igt_wait_for_vblank(data->drm_fd, data->pipe);
 
 	/* get reference crc for fb[1] */
-	igt_pipe_crc_start(pipe_crc);
-	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
-	data->ref_crc[1] = crcs[0];
-	igt_pipe_crc_stop(pipe_crc);
-	free(crcs);
+	igt_pipe_crc_collect_crc(pipe_crc, &data->ref_crc[1]);
 
 	if (test_mode == TEST_CONTEXT || test_mode == TEST_PAGE_FLIP_AND_CONTEXT) {
 		data->ctx[0] = drm_intel_gem_context_create(data->bufmgr);
@@ -406,11 +395,7 @@ static bool prepare_test(data_t *data, enum test_mode test_mode)
 	igt_wait_for_vblank(data->drm_fd, data->pipe);
 
 	/* get reference crc for fb[0] */
-	igt_pipe_crc_start(pipe_crc);
-	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
-	data->ref_crc[0] = crcs[0];
-	igt_pipe_crc_stop(pipe_crc);
-	free(crcs);
+	igt_pipe_crc_collect_crc(pipe_crc, &data->ref_crc[0]);
 
 	return true;
 }
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 6/7] tests/kms_fbc_crc: remove redundant information from data_t
  2015-03-25 21:50 [PATCH 1/7] lib: add igt_wait() Paulo Zanoni
                   ` (3 preceding siblings ...)
  2015-03-25 21:50 ` [PATCH 5/7] tests/kms_fbc_crc: use igt_pipe_crc_collect_crc() Paulo Zanoni
@ 2015-03-25 21:50 ` Paulo Zanoni
  2015-03-25 21:50 ` [PATCH 7/7] lib: add igt_draw Paulo Zanoni
  5 siblings, 0 replies; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-25 21:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

While it is nice to have shorter names for the most-accessed
variables, it makes the code more difficult to read since it's not
clear to the code reader whether that "gem_handle" is from some FB or
something else. The reader also has to audit the code to see if, for
example, the value of data->handle[0] stays consistent with
data->fb[0].gem_handle all the tame or if at some point the value is
replaced with something else. So remove the redundant information,
making it explicit that we're using the gem handles and FB IDs of the
framebuffers all the time.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 tests/kms_fbc_crc.c | 43 +++++++++++++++++++------------------------
 1 file changed, 19 insertions(+), 24 deletions(-)

diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
index f1888c4..abdc065 100644
--- a/tests/kms_fbc_crc.c
+++ b/tests/kms_fbc_crc.c
@@ -61,13 +61,11 @@ typedef struct {
 	drm_intel_bufmgr *bufmgr;
 	drm_intel_context *ctx[2];
 	uint32_t devid;
-	uint32_t handle[2];
 	igt_display_t display;
 	igt_output_t *output;
 	enum pipe pipe;
 	igt_plane_t *primary;
 	struct igt_fb fb[2];
-	uint32_t fb_id[2];
 } data_t;
 
 static const char *test_mode_str(enum test_mode mode)
@@ -216,14 +214,14 @@ static void test_crc(data_t *data, enum test_mode mode)
 	uint32_t crtc_id = data->output->config.crtc->crtc_id;
 	igt_pipe_crc_t *pipe_crc = data->pipe_crc;
 	igt_crc_t crc;
-	uint32_t handle = data->handle[0];
+	uint32_t handle = data->fb[0].gem_handle;
 
 	igt_assert(fbc_enabled(data));
 
 	if (mode >= TEST_PAGE_FLIP_AND_MMAP_CPU) {
-		handle = data->handle[1];
+		handle = data->fb[1].gem_handle;
 		igt_assert(drmModePageFlip(data->drm_fd, crtc_id,
-					   data->fb_id[1], 0, NULL) == 0);
+					   data->fb[1].fb_id, 0, NULL) == 0);
 
 		igt_assert(wait_for_fbc_enabled(data));
 	}
@@ -232,7 +230,7 @@ static void test_crc(data_t *data, enum test_mode mode)
 		void *ptr;
 	case TEST_PAGE_FLIP:
 		igt_assert(drmModePageFlip(data->drm_fd, crtc_id,
-					   data->fb_id[1], 0, NULL) == 0);
+					   data->fb[1].fb_id, 0, NULL) == 0);
 		break;
 	case TEST_MMAP_CPU:
 	case TEST_PAGE_FLIP_AND_MMAP_CPU:
@@ -314,24 +312,21 @@ static bool prepare_test(data_t *data, enum test_mode test_mode)
 	igt_output_t *output = data->output;
 	drmModeModeInfo *mode;
 	igt_pipe_crc_t *pipe_crc;
+	int rc;
 
 	data->primary = igt_output_get_plane(data->output, IGT_PLANE_PRIMARY);
 	mode = igt_output_get_mode(data->output);
 
-	data->fb_id[0] = igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
-					     DRM_FORMAT_XRGB8888,
-					     LOCAL_I915_FORMAT_MOD_X_TILED,
-					     0.0, 0.0, 0.0, &data->fb[0]);
-	igt_assert(data->fb_id[0]);
-	data->fb_id[1] = igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
-					     DRM_FORMAT_XRGB8888,
-					     LOCAL_I915_FORMAT_MOD_X_TILED,
-					     0.1, 0.1, 0.1,
-					     &data->fb[1]);
-	igt_assert(data->fb_id[1]);
-
-	data->handle[0] = data->fb[0].gem_handle;
-	data->handle[1] = data->fb[1].gem_handle;
+	rc = igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+				 DRM_FORMAT_XRGB8888,
+				 LOCAL_I915_FORMAT_MOD_X_TILED,
+				 0.0, 0.0, 0.0, &data->fb[0]);
+	igt_assert(rc);
+	rc = igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+				 DRM_FORMAT_XRGB8888,
+				 LOCAL_I915_FORMAT_MOD_X_TILED,
+				 0.1, 0.1, 0.1, &data->fb[1]);
+	igt_assert(rc);
 
 	/* scanout = fb[1] */
 	igt_plane_set_fb(data->primary, &data->fb[1]);
@@ -372,10 +367,10 @@ static bool prepare_test(data_t *data, enum test_mode test_mode)
 		 * Disable FBC RT address for both contexts
 		 * (by "rendering" to a non-scanout buffer).
 		 */
-		exec_nop(data, data->handle[0], data->ctx[1]);
-		exec_nop(data, data->handle[0], data->ctx[0]);
-		exec_nop(data, data->handle[0], data->ctx[1]);
-		exec_nop(data, data->handle[0], data->ctx[0]);
+		exec_nop(data, data->fb[0].gem_handle, data->ctx[1]);
+		exec_nop(data, data->fb[0].gem_handle, data->ctx[0]);
+		exec_nop(data, data->fb[0].gem_handle, data->ctx[1]);
+		exec_nop(data, data->fb[0].gem_handle, data->ctx[0]);
 	}
 
 	/* scanout = fb[0] */
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 7/7] lib: add igt_draw
  2015-03-25 21:50 [PATCH 1/7] lib: add igt_wait() Paulo Zanoni
                   ` (4 preceding siblings ...)
  2015-03-25 21:50 ` [PATCH 6/7] tests/kms_fbc_crc: remove redundant information from data_t Paulo Zanoni
@ 2015-03-25 21:50 ` Paulo Zanoni
  2015-03-26 10:19   ` Daniel Vetter
  5 siblings, 1 reply; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-25 21:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

For all those IGT tests that need an easy way to draw rectangles on
buffers using different methods. Current planned users: FBC and PSR
CRC tests.

There is also a lib/tests/igt_draw program to check if the library is
sane.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 lib/Makefile.sources       |   2 +
 lib/igt_draw.c             | 467 +++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_draw.h             |  54 ++++++
 lib/tests/.gitignore       |   1 +
 lib/tests/Makefile.sources |   1 +
 lib/tests/igt_draw.c       | 247 ++++++++++++++++++++++++
 6 files changed, 772 insertions(+)
 create mode 100644 lib/igt_draw.c
 create mode 100644 lib/igt_draw.h
 create mode 100644 lib/tests/igt_draw.c

diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 3d93629..85dc321 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -52,6 +52,8 @@ libintel_tools_la_SOURCES = 	\
 	igt_fb.h		\
 	igt_core.c		\
 	igt_core.h		\
+	igt_draw.c		\
+	igt_draw.h		\
 	$(NULL)
 
 .PHONY: version.h.tmp
diff --git a/lib/igt_draw.c b/lib/igt_draw.c
new file mode 100644
index 0000000..4eb7507
--- /dev/null
+++ b/lib/igt_draw.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <sys/mman.h>
+
+#include "igt_draw.h"
+
+#include "drmtest.h"
+#include "intel_chipset.h"
+#include "igt_core.h"
+#include "igt_fb.h"
+#include "ioctl_wrappers.h"
+
+/**
+ * SECTION:igt_draw
+ * @short_description: drawing helpers for tests
+ * @title: i-g-t draw
+ * @include: igt_draw.h
+ *
+ * This library contains some functions for drawing rectangles on buffers using
+ * the many different drawing methods we have. It also contains some wrappers
+ * that make the process easier if you have the abstract objects in hand.
+ *
+ * All functions assume the buffers are in the XRGB 8:8:8 format.
+ *
+ */
+
+/* Some internal data structures to avoid having to pass tons of parameters
+ * around everything. */
+struct cmd_data {
+	drm_intel_bufmgr *bufmgr;
+	drm_intel_context *context;
+};
+
+struct buf_data {
+	uint32_t handle;
+	uint32_t size;
+	uint32_t stride;
+};
+
+struct rect {
+	int x;
+	int y;
+	int w;
+	int h;
+};
+
+const char *igt_draw_get_method_name(enum igt_draw_method method)
+{
+	switch (method) {
+	case IGT_DRAW_MMAP_CPU:
+		return "mmap-cpu";
+	case IGT_DRAW_MMAP_GTT:
+		return "mmap-gtt";
+	case IGT_DRAW_PWRITE:
+		return "pwrite";
+	case IGT_DRAW_BLT:
+		return "blt";
+	case IGT_DRAW_RENDER:
+		return "render";
+	default:
+		igt_assert(false);
+	}
+}
+
+static int swizzle_addr(int addr, int swizzle)
+{
+	int bit6;
+
+	if (swizzle == I915_BIT_6_SWIZZLE_9_10) {
+		bit6 = ((addr >> 6) & 1) ^ ((addr >> 9) & 1) ^
+		       ((addr >> 10) & 1);
+		addr &= ~(1 << 6);
+		addr |= (bit6 << 6);
+	}
+
+	return addr;
+}
+
+/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
+ * if you need to. */
+static int linear_x_y_to_tiled_pos(int x, int y, uint32_t stride, int swizzle)
+{
+	int x_tile_size, y_tile_size;
+	int x_tile_n, y_tile_n, x_tile_off, y_tile_off;
+	int line_size, tile_size;
+	int tile_n, tile_off;
+	int tiled_pos, tiles_per_line;
+	int bpp;
+
+	line_size = stride;
+	x_tile_size = 512;
+	y_tile_size = 8;
+	tile_size = x_tile_size * y_tile_size;
+	tiles_per_line = line_size / x_tile_size;
+	bpp = sizeof(uint32_t);
+
+	y_tile_n = y / y_tile_size;
+	y_tile_off = y % y_tile_size;
+
+	x_tile_n = (x * bpp) / x_tile_size;
+	x_tile_off = (x * bpp) % x_tile_size;
+
+	tile_n = y_tile_n * tiles_per_line + x_tile_n;
+	tile_off = y_tile_off * x_tile_size + x_tile_off;
+	tiled_pos = tile_n * tile_size + tile_off;
+
+	tiled_pos = swizzle_addr(tiled_pos, swizzle);
+
+	return tiled_pos / bpp;
+}
+
+/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
+ * if you need to. */
+static void tiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
+				    int swizzle, int *x, int *y)
+{
+	int tile_n, tile_off, tiles_per_line, line_size;
+	int x_tile_off, y_tile_off;
+	int x_tile_n, y_tile_n;
+	int x_tile_size, y_tile_size, tile_size;
+	int bpp;
+
+	tiled_pos = swizzle_addr(tiled_pos, swizzle);
+
+	line_size = stride;
+	x_tile_size = 512;
+	y_tile_size = 8;
+	tile_size = x_tile_size * y_tile_size;
+	tiles_per_line = line_size / x_tile_size;
+	bpp = sizeof(uint32_t);
+
+	tile_n = tiled_pos / tile_size;
+	tile_off = tiled_pos % tile_size;
+
+	y_tile_off = tile_off / x_tile_size;
+	x_tile_off = tile_off % x_tile_size;
+
+	x_tile_n = tile_n % tiles_per_line;
+	y_tile_n = tile_n / tiles_per_line;
+
+	*x = (x_tile_n * x_tile_size + x_tile_off) / bpp;
+	*y = y_tile_n * y_tile_size + y_tile_off;
+}
+
+static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
+			       uint32_t color)
+{
+	uint32_t *ptr;
+	int x, y, pos;
+	uint32_t tiling, swizzle;
+
+	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
+		       I915_GEM_DOMAIN_CPU);
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	ptr = gem_mmap__cpu(fd, buf->handle, 0, buf->size, 0);
+	igt_assert(ptr);
+
+	for (y = rect->y; y < rect->y + rect->h; y++) {
+		for (x = rect->x; x < rect->x + rect->w; x++) {
+			if (tiling)
+				pos = linear_x_y_to_tiled_pos(x, y, buf->stride,
+							      swizzle);
+			else
+				pos = (y * buf->stride / sizeof(uint32_t)) + x;
+			ptr[pos] = color;
+		}
+	}
+
+	gem_sw_finish(fd, buf->handle);
+
+	igt_assert(munmap(ptr, buf->size) == 0);
+}
+
+static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
+			       uint32_t color)
+{
+	uint32_t *ptr;
+	int x, y;
+
+	ptr = gem_mmap__gtt(fd, buf->handle, buf->size,
+			    PROT_READ | PROT_WRITE);
+	igt_assert(ptr);
+
+	for (y = rect->y; y < rect->y + rect->h; y++) {
+		int line_begin = y * buf->stride / sizeof(uint32_t);
+		for (x = rect->x; x < rect->x + rect->w; x++)
+			ptr[line_begin + x] = color;
+	}
+
+	igt_assert(munmap(ptr, buf->size) == 0);
+}
+
+static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
+				     struct rect *rect, uint32_t color)
+{
+	uint32_t tmp[rect->w];
+	int i, y, offset, bpp;
+
+	bpp = sizeof(uint32_t);
+
+	for (i = 0; i < rect->w; i++)
+		tmp[i] = color;
+
+	for (y = rect->y; y < rect->y + rect->h; y++) {
+		offset = (y * buf->stride) + (rect->x * bpp);
+		gem_write(fd, buf->handle, offset, tmp, rect->w * bpp);
+	}
+}
+
+static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
+				   struct rect *rect, uint32_t color,
+				   uint32_t swizzle)
+{
+	int i;
+	int tiled_pos, bpp, x, y;
+	uint32_t tmp[1024];
+	int tmp_used = 0, tmp_size = ARRAY_SIZE(tmp);
+	bool flush_tmp = false;
+	int tmp_start_pos = 0;
+
+	bpp = sizeof(uint32_t);
+
+	/* Instead of doing one pwrite per pixel, we try to group the maximum
+	 * amount of consecutive pixels we can in a single pwrite: that's why we
+	 * use the "tmp" variables. */
+	for (i = 0; i < tmp_size; i++)
+		tmp[i] = color;
+
+	for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += bpp) {
+		tiled_pos_to_x_y_linear(tiled_pos, buf->stride, swizzle, &x, &y);
+
+		if (x >= rect->x && x < rect->x + rect->w &&
+		    y >= rect->y && y < rect->y + rect->h) {
+			if (tmp_used == 0)
+				tmp_start_pos = tiled_pos;
+			tmp_used++;
+		} else {
+			flush_tmp = true;
+		}
+
+		if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0)) {
+			gem_write(fd, buf->handle, tmp_start_pos, tmp,
+				  tmp_used * bpp);
+			flush_tmp = false;
+			tmp_used = 0;
+		}
+	}
+}
+
+static void draw_rect_pwrite(int fd, struct buf_data *buf,
+			     struct rect *rect, uint32_t color)
+{
+	uint32_t tiling, swizzle;
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	if (tiling)
+		draw_rect_pwrite_tiled(fd, buf, rect, color, swizzle);
+	else
+		draw_rect_pwrite_untiled(fd, buf, rect, color);
+}
+
+static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
+			  struct buf_data *buf, struct rect *rect,
+			  uint32_t color)
+{
+	drm_intel_bo *dst;
+	struct intel_batchbuffer *batch;
+	int blt_cmd_len, blt_cmd_tiling;
+	uint32_t devid = intel_get_drm_devid(fd);
+	int gen = intel_gen(devid);
+	uint32_t tiling, swizzle;
+	int pitch;
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
+	igt_assert(dst);
+
+	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
+	igt_assert(batch);
+
+	blt_cmd_len = (gen >= 8) ?  0x5 : 0x4;
+	blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
+	pitch = (tiling) ? buf->stride / 4 : buf->stride;
+
+	BEGIN_BATCH(6, 1);
+	OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
+		  XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
+	OUT_BATCH((3 << 24) | (0xF0 << 16) | pitch);
+	OUT_BATCH((rect->y << 16) | rect->x);
+	OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
+	if (tiling)
+		OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
+	else
+		OUT_RELOC(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
+	OUT_BATCH(color);
+	ADVANCE_BATCH();
+
+	intel_batchbuffer_flush(batch);
+	gem_sync(fd, buf->handle);
+	intel_batchbuffer_free(batch);
+}
+
+static void draw_rect_render(int fd, struct cmd_data *cmd_data,
+			     struct buf_data *buf, struct rect *rect,
+			     uint32_t color)
+{
+	drm_intel_bo *src, *dst;
+	uint32_t devid = intel_get_drm_devid(fd);
+	igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
+	struct igt_buf src_buf, dst_buf;
+	struct intel_batchbuffer *batch;
+	uint32_t tiling, swizzle;
+	struct buf_data tmp;
+
+	igt_skip_on(!rendercopy);
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	/* We create a temporary buffer and copy from it using rendercopy. */
+	tmp.size = rect->w * rect->h * sizeof(uint32_t);
+	tmp.handle = gem_create(fd, tmp.size);
+	tmp.stride = rect->w * sizeof(uint32_t);
+	draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
+			   color);
+
+	src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
+	igt_assert(src);
+	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
+	igt_assert(dst);
+
+	src_buf.bo = src;
+	src_buf.stride = tmp.stride;
+	src_buf.tiling = I915_TILING_NONE;
+	src_buf.size = tmp.size;
+	dst_buf.bo = dst;
+	dst_buf.stride = buf->stride;
+	dst_buf.tiling = tiling;
+	dst_buf.size = buf->size;
+
+	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
+	igt_assert(batch);
+
+	rendercopy(batch, cmd_data->context, &src_buf, 0, 0, rect->w, rect->h,
+		   &dst_buf, rect->x, rect->y);
+
+	gem_sync(fd, buf->handle);
+	intel_batchbuffer_free(batch);
+	gem_close(fd, tmp.handle);
+}
+
+/**
+ * igt_draw_rect:
+ * @fd: the DRM file descriptor
+ * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
+ *          IGT_DRAW_RENDER
+ * @context: the context, can be NULL if you don't want to think about it
+ * @buf_handle: the handle of the buffer where you're going to draw to
+ * @buf_size: the size of the buffer
+ * @buf_stride: the stride of the buffer
+ * @method: method you're going to use to write to the buffer
+ * @rect_x: horizontal position on the buffer where your rectangle starts
+ * @rect_y: vertical position on the buffer where your rectangle starts
+ * @rect_w: width of the rectangle
+ * @rect_h: height of the rectangle
+ * @color: color of the rectangle
+ *
+ * This function draws a colored rectangle on the destination buffer, allowing
+ * you to specify the method used to draw the rectangle. We assume 32 bit pixels
+ * with 8 bits per color.
+ */
+void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
+		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
+		   enum igt_draw_method method, int rect_x, int rect_y,
+		   int rect_w, int rect_h, uint32_t color)
+{
+	struct cmd_data cmd_data = {
+		.bufmgr = bufmgr,
+		.context = context,
+	};
+	struct buf_data buf = {
+		.handle = buf_handle,
+		.size = buf_size,
+		.stride = buf_stride,
+	};
+	struct rect rect = {
+		.x = rect_x,
+		.y = rect_y,
+		.w = rect_w,
+		.h = rect_h,
+	};
+
+	switch (method) {
+	case IGT_DRAW_MMAP_CPU:
+		draw_rect_mmap_cpu(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_MMAP_GTT:
+		draw_rect_mmap_gtt(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_PWRITE:
+		draw_rect_pwrite(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_BLT:
+		draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
+		break;
+	case IGT_DRAW_RENDER:
+		draw_rect_render(fd, &cmd_data, &buf, &rect, color);
+		break;
+	default:
+		igt_assert(false);
+		break;
+	}
+}
+
+/**
+ * igt_draw_rect_fb:
+ *
+ * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
+ * of manually providing its details. See igt_draw_rect.
+ */
+void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
+		      drm_intel_context *context, struct igt_fb *fb,
+		      enum igt_draw_method method, int rect_x, int rect_y,
+		      int rect_w, int rect_h, uint32_t color)
+{
+	igt_draw_rect(fd, bufmgr, context, fb->gem_handle, fb->size, fb->stride,
+		      method, rect_x, rect_y, rect_w, rect_h, color);
+}
+
+/**
+ * igt_draw_fill_fb:
+ * @fd: the DRM file descriptor
+ * @fb: the FB that is going to be filled
+ * @color: the color you're going to paint it
+ *
+ * This function just paints an igt_fb using the provided color. It assumes 32
+ * bit pixels with 8 bit colors.
+ */
+void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
+{
+	igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
+			 0, 0, fb->width, fb->height, color);
+}
diff --git a/lib/igt_draw.h b/lib/igt_draw.h
new file mode 100644
index 0000000..399e17c
--- /dev/null
+++ b/lib/igt_draw.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __IGT_DRAW_H__
+#define __IGT_DRAW_H__
+
+#include <intel_bufmgr.h>
+#include "igt_fb.h"
+
+enum igt_draw_method {
+	IGT_DRAW_MMAP_CPU,
+	IGT_DRAW_MMAP_GTT,
+	IGT_DRAW_PWRITE,
+	IGT_DRAW_BLT,
+	IGT_DRAW_RENDER,
+	IGT_DRAW_METHOD_COUNT,
+};
+
+const char *igt_draw_get_method_name(enum igt_draw_method method);
+
+void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
+		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
+		   enum igt_draw_method method, int rect_x, int rect_y,
+		   int rect_w, int rect_h, uint32_t color);
+
+void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
+		      drm_intel_context *context, struct igt_fb *fb,
+		      enum igt_draw_method method, int rect_x, int rect_y,
+		      int rect_w, int rect_h, uint32_t color);
+
+void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color);
+
+#endif /* __IGT_DRAW_H__ */
diff --git a/lib/tests/.gitignore b/lib/tests/.gitignore
index a745a23..88f668a 100644
--- a/lib/tests/.gitignore
+++ b/lib/tests/.gitignore
@@ -1,4 +1,5 @@
 # Please keep sorted alphabetically
+igt_draw
 igt_fork_helper
 igt_invalid_subtest_name
 igt_list_only
diff --git a/lib/tests/Makefile.sources b/lib/tests/Makefile.sources
index ecd73ae..ff66d9d 100644
--- a/lib/tests/Makefile.sources
+++ b/lib/tests/Makefile.sources
@@ -1,4 +1,5 @@
 check_PROGRAMS = \
+	igt_draw \
 	igt_no_exit \
 	igt_no_exit_list_only \
 	igt_fork_helper \
diff --git a/lib/tests/igt_draw.c b/lib/tests/igt_draw.c
new file mode 100644
index 0000000..1630cc2
--- /dev/null
+++ b/lib/tests/igt_draw.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+/* This program tests whether the igt_draw library actually works. */
+
+#include "drmtest.h"
+#include "igt_aux.h"
+#include "igt_draw.h"
+#include "igt_debugfs.h"
+#include "igt_fb.h"
+#include "igt_kms.h"
+
+#define MAX_CONNECTORS 32
+
+struct modeset_params {
+	uint32_t crtc_id;
+	uint32_t connector_id;
+	drmModeModeInfoPtr mode;
+};
+
+int drm_fd;
+drmModeResPtr drm_res;
+drmModeConnectorPtr drm_connectors[MAX_CONNECTORS];
+drm_intel_bufmgr *bufmgr;
+igt_pipe_crc_t *pipe_crc;
+
+bool has_method_base_crc = false;
+igt_crc_t method_base_crc;
+
+struct modeset_params ms;
+
+static void find_modeset_params(void)
+{
+	int i;
+	uint32_t connector_id = 0, crtc_id;
+	drmModeModeInfoPtr mode = NULL;
+
+	for (i = 0; i < drm_res->count_connectors; i++) {
+		drmModeConnectorPtr c = drm_connectors[i];
+
+		if (c->count_modes) {
+			connector_id = c->connector_id;
+			mode = &c->modes[0];
+			break;
+		}
+	}
+	igt_require(connector_id);
+
+	crtc_id = drm_res->crtcs[0];
+	igt_assert(crtc_id);
+	igt_assert(mode);
+
+	ms.connector_id = connector_id;
+	ms.crtc_id = crtc_id;
+	ms.mode = mode;
+
+}
+
+static void get_method_crc(enum igt_draw_method method, uint64_t tiling,
+			   igt_crc_t *crc)
+{
+	struct igt_fb fb;
+	int rc;
+
+	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
+		      DRM_FORMAT_XRGB8888, tiling, &fb);
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 0, 0, fb.width, fb.height, 0xFF);
+
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 fb.width / 4, fb.height / 4,
+			 fb.width / 2, fb.height / 2, 0xFF00);
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 fb.width / 8, fb.height / 8,
+			 fb.width / 4, fb.height / 4, 0xFF0000);
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 fb.width / 2, fb.height / 2,
+			 fb.width / 3, fb.height / 3, 0xFF00FF);
+
+	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
+			    &ms.connector_id, 1, ms.mode);
+	igt_assert(rc == 0);
+
+	igt_debug_wait_for_keypress("crc");
+	igt_pipe_crc_collect_crc(pipe_crc, crc);
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+	igt_remove_fb(drm_fd, &fb);
+}
+
+static void draw_method_subtest(enum igt_draw_method method, uint64_t tiling)
+{
+	igt_crc_t crc;
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+
+	find_modeset_params();
+
+	/* Use IGT_DRAW_MMAP_GTT on an untiled buffer as the parameter for
+	 * comparison. Cache the value so we don't recompute it for every single
+	 * subtest. */
+	if (!has_method_base_crc) {
+		get_method_crc(IGT_DRAW_MMAP_GTT, LOCAL_DRM_FORMAT_MOD_NONE,
+			       &method_base_crc);
+		has_method_base_crc = true;
+	}
+
+	get_method_crc(method, tiling, &crc);
+	igt_assert_crc_equal(&crc, &method_base_crc);
+}
+
+static void get_fill_crc(uint64_t tiling, igt_crc_t *crc)
+{
+	struct igt_fb fb;
+	int rc;
+
+	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
+		      DRM_FORMAT_XRGB8888, tiling, &fb);
+
+	igt_draw_fill_fb(drm_fd, &fb, 0xFF);
+
+	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
+			    &ms.connector_id, 1, ms.mode);
+	igt_assert(rc == 0);
+
+	igt_debug_wait_for_keypress("crc");
+	igt_pipe_crc_collect_crc(pipe_crc, crc);
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+	igt_remove_fb(drm_fd, &fb);
+}
+
+static void fill_fb_subtest(void)
+{
+	int rc;
+	struct igt_fb fb;
+	igt_crc_t base_crc, crc;
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+
+	find_modeset_params();
+
+	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
+		      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb);
+
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, IGT_DRAW_MMAP_GTT,
+			 0, 0, fb.width, fb.height, 0xFF);
+
+	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
+			    &ms.connector_id, 1, ms.mode);
+	igt_assert(rc == 0);
+
+	igt_debug_wait_for_keypress("crc");
+	igt_pipe_crc_collect_crc(pipe_crc, &base_crc);
+
+	get_fill_crc(LOCAL_DRM_FORMAT_MOD_NONE, &crc);
+	igt_assert_crc_equal(&crc, &base_crc);
+
+	get_fill_crc(LOCAL_I915_FORMAT_MOD_X_TILED, &crc);
+	igt_assert_crc_equal(&crc, &base_crc);
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+	igt_remove_fb(drm_fd, &fb);
+}
+
+static void setup_environment(void)
+{
+	int i;
+
+	drm_fd = drm_open_any_master();
+	igt_require(drm_fd >= 0);
+
+	drm_res = drmModeGetResources(drm_fd);
+	igt_assert(drm_res->count_connectors <= MAX_CONNECTORS);
+
+	for (i = 0; i < drm_res->count_connectors; i++)
+		drm_connectors[i] = drmModeGetConnector(drm_fd,
+							drm_res->connectors[i]);
+
+	kmstest_set_vt_graphics_mode();
+
+	bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
+	igt_assert(bufmgr);
+	drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+	pipe_crc = igt_pipe_crc_new(0, INTEL_PIPE_CRC_SOURCE_AUTO);
+}
+
+static void teardown_environment(void)
+{
+	int i;
+
+	igt_pipe_crc_free(pipe_crc);
+
+	drm_intel_bufmgr_destroy(bufmgr);
+
+	for (i = 0; i < drm_res->count_connectors; i++)
+		drmModeFreeConnector(drm_connectors[i]);
+
+	drmModeFreeResources(drm_res);
+	close(drm_fd);
+}
+
+igt_main
+{
+	enum igt_draw_method method;
+
+	igt_fixture
+		setup_environment();
+
+	for (method = 0; method < IGT_DRAW_METHOD_COUNT; method++) {
+		igt_subtest_f("draw-method-%s-untiled",
+			      igt_draw_get_method_name(method))
+			draw_method_subtest(method, LOCAL_DRM_FORMAT_MOD_NONE);
+		igt_subtest_f("draw-method-%s-tiled",
+			      igt_draw_get_method_name(method))
+			draw_method_subtest(method,
+					    LOCAL_I915_FORMAT_MOD_X_TILED);
+	}
+
+	igt_subtest("fill-fb")
+		fill_fb_subtest();
+
+	igt_fixture
+		teardown_environment();
+}
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH 2/7] tests/kms_fb_crc: call gem_sync() instead of gem_bo_busy()
  2015-03-25 21:50 ` [PATCH 2/7] tests/kms_fb_crc: call gem_sync() instead of gem_bo_busy() Paulo Zanoni
@ 2015-03-26 10:06   ` Daniel Vetter
  0 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2015-03-26 10:06 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: intel-gfx, Paulo Zanoni

On Wed, Mar 25, 2015 at 06:50:34PM -0300, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> 
> The way kms_fbc_crc works is that it does an operation that may
> trigger/invalidate/update FBC, then it sleeps for 300ms to wait for
> FBC to kick in again, then it calls "igt_assert(fbc_enabled())".
> 
> This was causing problems where the BLT test would eventually fail in
> the fbc_eanbled() assertion.
> 
> With the recent FBC move to front buffer rendering tracking, if we
> don't call gem_sync() after submitting render and blt commands, it may
> take much more than 300ms for FBC to be reenabled:
> i915_gem_execbuffer2() indirectly calls intel_fb_obj_invalidate(),
> which disables FBC, and then it is only reenabled when
> i915_gem_retire_work_handler() happens and indirectly calls
> intel_frontbuffer_flush(). Notice that while FBC is not yet enabled,
> the screen contents are correct, so this shouldn't really be a "bug".
> 
> The gem_sync() call will make sure the long waits don't happen. With
> this, 300ms should be much more than enough: either we wait about 50ms
> for FBC to be re-enabled - intel_enable_fbc() uses a delayed work - or
> it's instantaneous - on the cases where we just do the nuke.
> 
> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

Hm maybe we should have 2 subtests: One with the bo_busy which only checks
that the screen contents is right. And then after a longer delay checks
that fbc gets reentered eventually. One with the gem_sync which also makes
sure fbc gets reentered more timely.
-Daniel

> ---
>  tests/kms_fbc_crc.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
> index 4256fed..b3e6109 100644
> --- a/tests/kms_fbc_crc.c
> +++ b/tests/kms_fbc_crc.c
> @@ -122,7 +122,7 @@ static void fill_blt(data_t *data,
>  	intel_batchbuffer_flush(batch);
>  	intel_batchbuffer_free(batch);
>  
> -	gem_bo_busy(data->drm_fd, handle);
> +	gem_sync(data->drm_fd, handle);
>  }
>  
>  static void scratch_buf_init(struct igt_buf *buf, drm_intel_bo *bo)
> @@ -187,7 +187,7 @@ static void fill_render(data_t *data, uint32_t handle,
>  
>  	intel_batchbuffer_free(batch);
>  
> -	gem_bo_busy(data->drm_fd, handle);
> +	gem_sync(data->drm_fd, handle);
>  }
>  
>  static bool fbc_enabled(data_t *data)
> -- 
> 2.1.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/7] tests/kms_fbc_crc: add wait_for_fbc_enabled()
  2015-03-25 21:50 ` [PATCH 3/7] tests/kms_fbc_crc: add wait_for_fbc_enabled() Paulo Zanoni
@ 2015-03-26 10:07   ` Daniel Vetter
  0 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2015-03-26 10:07 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: intel-gfx, Paulo Zanoni

On Wed, Mar 25, 2015 at 06:50:35PM -0300, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> 
> The code has a common pattern of "wait 300ms, then check if FBC is
> enabled". Most of the time FBC is enabled in either 50ms or 0ms, so
> introduce wait_for_fbc_enabled(), which can return much earlier if FBC
> is actually enabled before the 300ms timeout.
> 
> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>

If we go with my suggestion in the previous mail this would need a
configurable timeout - with just gem_bo_busy we'd need a 2second timeout
or similar.
-Daniel

> ---
>  tests/kms_fbc_crc.c | 19 ++++++++++---------
>  1 file changed, 10 insertions(+), 9 deletions(-)
> 
> diff --git a/tests/kms_fbc_crc.c b/tests/kms_fbc_crc.c
> index b3e6109..11078e0 100644
> --- a/tests/kms_fbc_crc.c
> +++ b/tests/kms_fbc_crc.c
> @@ -28,6 +28,7 @@
>  #include <string.h>
>  
>  #include "drmtest.h"
> +#include "igt_aux.h"
>  #include "igt_debugfs.h"
>  #include "igt_kms.h"
>  #include "intel_chipset.h"
> @@ -203,6 +204,11 @@ static bool fbc_enabled(data_t *data)
>  	return strstr(str, "FBC enabled") != NULL;
>  }
>  
> +static bool wait_for_fbc_enabled(data_t *data)
> +{
> +	return igt_wait(fbc_enabled(data), 300, 30);
> +}
> +
>  static void test_crc(data_t *data, enum test_mode mode)
>  {
>  	uint32_t crtc_id = data->output->config.crtc->crtc_id;
> @@ -216,9 +222,8 @@ static void test_crc(data_t *data, enum test_mode mode)
>  		handle = data->handle[1];
>  		igt_assert(drmModePageFlip(data->drm_fd, crtc_id,
>  					   data->fb_id[1], 0, NULL) == 0);
> -		usleep(300000);
>  
> -		igt_assert(fbc_enabled(data));
> +		igt_assert(wait_for_fbc_enabled(data));
>  	}
>  
>  	switch (mode) {
> @@ -277,9 +282,7 @@ static void test_crc(data_t *data, enum test_mode mode)
>  	 * Allow time for FBC to kick in again if it
>  	 * got disabled during dirtyfb or page flip.
>  	 */
> -	usleep(300000);
> -
> -	igt_assert(fbc_enabled(data));
> +	igt_assert(wait_for_fbc_enabled(data));
>  
>  	igt_pipe_crc_start(pipe_crc);
>  	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
> @@ -338,9 +341,8 @@ static bool prepare_test(data_t *data, enum test_mode test_mode)
>  	/* scanout = fb[1] */
>  	igt_plane_set_fb(data->primary, &data->fb[1]);
>  	igt_display_commit(display);
> -	usleep(300000);
>  
> -	if (!fbc_enabled(data)) {
> +	if (!wait_for_fbc_enabled(data)) {
>  		igt_info("FBC not enabled\n");
>  
>  		igt_plane_set_fb(data->primary, NULL);
> @@ -388,9 +390,8 @@ static bool prepare_test(data_t *data, enum test_mode test_mode)
>  	/* scanout = fb[0] */
>  	igt_plane_set_fb(data->primary, &data->fb[0]);
>  	igt_display_commit(display);
> -	usleep(300000);
>  
> -	igt_assert(fbc_enabled(data));
> +	igt_assert(wait_for_fbc_enabled(data));
>  
>  	if (test_mode == TEST_CONTEXT || test_mode == TEST_PAGE_FLIP_AND_CONTEXT) {
>  		/*
> -- 
> 2.1.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-03-25 21:50 ` [PATCH 7/7] lib: add igt_draw Paulo Zanoni
@ 2015-03-26 10:19   ` Daniel Vetter
  2015-03-30 19:45     ` Paulo Zanoni
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2015-03-26 10:19 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: intel-gfx, Paulo Zanoni

On Wed, Mar 25, 2015 at 06:50:39PM -0300, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> 
> For all those IGT tests that need an easy way to draw rectangles on
> buffers using different methods. Current planned users: FBC and PSR
> CRC tests.
> 
> There is also a lib/tests/igt_draw program to check if the library is
> sane.

We need to move that to tests/igt_draw. The testcase in lib/tests/* get
run with make check, which must be possible as non-root on a non-intel
(build) machine. If you need an gpu to run your test it must be in tests/*
as a normal igt kernel test.

Wrt the library itself I'm unsure about the explicit tiling/swizzling.
Your current code only works on gen5-8 and maintaining a full-blown
swizzle/tiling library is real work, and means some of the tests can't be
converted to this. We do have all the tiling modes encoded in the tiling
tests though, so if you have a lot of time it might be useful to extract
tiling helpers into the igt library which work on all generations.

I think we should at least have a fallback mode which allows us to fill an
entire buffer completely (i.e. not just the hxw area) and treat it as
untiled.

More comments below.
-Daniel

> 
> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> ---
>  lib/Makefile.sources       |   2 +
>  lib/igt_draw.c             | 467 +++++++++++++++++++++++++++++++++++++++++++++
>  lib/igt_draw.h             |  54 ++++++
>  lib/tests/.gitignore       |   1 +
>  lib/tests/Makefile.sources |   1 +
>  lib/tests/igt_draw.c       | 247 ++++++++++++++++++++++++
>  6 files changed, 772 insertions(+)
>  create mode 100644 lib/igt_draw.c
>  create mode 100644 lib/igt_draw.h
>  create mode 100644 lib/tests/igt_draw.c
> 
> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> index 3d93629..85dc321 100644
> --- a/lib/Makefile.sources
> +++ b/lib/Makefile.sources
> @@ -52,6 +52,8 @@ libintel_tools_la_SOURCES = 	\
>  	igt_fb.h		\
>  	igt_core.c		\
>  	igt_core.h		\
> +	igt_draw.c		\
> +	igt_draw.h		\
>  	$(NULL)
>  
>  .PHONY: version.h.tmp
> diff --git a/lib/igt_draw.c b/lib/igt_draw.c
> new file mode 100644
> index 0000000..4eb7507
> --- /dev/null
> +++ b/lib/igt_draw.c
> @@ -0,0 +1,467 @@
> +/*
> + * Copyright © 2015 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#include <sys/mman.h>
> +
> +#include "igt_draw.h"
> +
> +#include "drmtest.h"
> +#include "intel_chipset.h"
> +#include "igt_core.h"
> +#include "igt_fb.h"
> +#include "ioctl_wrappers.h"
> +
> +/**
> + * SECTION:igt_draw
> + * @short_description: drawing helpers for tests
> + * @title: i-g-t draw
> + * @include: igt_draw.h
> + *
> + * This library contains some functions for drawing rectangles on buffers using
> + * the many different drawing methods we have. It also contains some wrappers
> + * that make the process easier if you have the abstract objects in hand.
> + *
> + * All functions assume the buffers are in the XRGB 8:8:8 format.
> + *
> + */
> +
> +/* Some internal data structures to avoid having to pass tons of parameters
> + * around everything. */
> +struct cmd_data {
> +	drm_intel_bufmgr *bufmgr;
> +	drm_intel_context *context;
> +};
> +
> +struct buf_data {
> +	uint32_t handle;
> +	uint32_t size;
> +	uint32_t stride;
> +};
> +
> +struct rect {
> +	int x;
> +	int y;
> +	int w;
> +	int h;
> +};
> +
> +const char *igt_draw_get_method_name(enum igt_draw_method method)
> +{
> +	switch (method) {
> +	case IGT_DRAW_MMAP_CPU:
> +		return "mmap-cpu";
> +	case IGT_DRAW_MMAP_GTT:
> +		return "mmap-gtt";
> +	case IGT_DRAW_PWRITE:
> +		return "pwrite";
> +	case IGT_DRAW_BLT:
> +		return "blt";
> +	case IGT_DRAW_RENDER:
> +		return "render";
> +	default:
> +		igt_assert(false);
> +	}
> +}
> +
> +static int swizzle_addr(int addr, int swizzle)
> +{
> +	int bit6;
> +
> +	if (swizzle == I915_BIT_6_SWIZZLE_9_10) {
> +		bit6 = ((addr >> 6) & 1) ^ ((addr >> 9) & 1) ^
> +		       ((addr >> 10) & 1);
> +		addr &= ~(1 << 6);
> +		addr |= (bit6 << 6);
> +	}
> +
> +	return addr;
> +}
> +
> +/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
> + * if you need to. */
> +static int linear_x_y_to_tiled_pos(int x, int y, uint32_t stride, int swizzle)
> +{
> +	int x_tile_size, y_tile_size;
> +	int x_tile_n, y_tile_n, x_tile_off, y_tile_off;
> +	int line_size, tile_size;
> +	int tile_n, tile_off;
> +	int tiled_pos, tiles_per_line;
> +	int bpp;
> +
> +	line_size = stride;
> +	x_tile_size = 512;
> +	y_tile_size = 8;
> +	tile_size = x_tile_size * y_tile_size;
> +	tiles_per_line = line_size / x_tile_size;
> +	bpp = sizeof(uint32_t);
> +
> +	y_tile_n = y / y_tile_size;
> +	y_tile_off = y % y_tile_size;
> +
> +	x_tile_n = (x * bpp) / x_tile_size;
> +	x_tile_off = (x * bpp) % x_tile_size;
> +
> +	tile_n = y_tile_n * tiles_per_line + x_tile_n;
> +	tile_off = y_tile_off * x_tile_size + x_tile_off;
> +	tiled_pos = tile_n * tile_size + tile_off;
> +
> +	tiled_pos = swizzle_addr(tiled_pos, swizzle);
> +
> +	return tiled_pos / bpp;
> +}
> +
> +/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
> + * if you need to. */
> +static void tiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
> +				    int swizzle, int *x, int *y)
> +{
> +	int tile_n, tile_off, tiles_per_line, line_size;
> +	int x_tile_off, y_tile_off;
> +	int x_tile_n, y_tile_n;
> +	int x_tile_size, y_tile_size, tile_size;
> +	int bpp;
> +
> +	tiled_pos = swizzle_addr(tiled_pos, swizzle);
> +
> +	line_size = stride;
> +	x_tile_size = 512;
> +	y_tile_size = 8;
> +	tile_size = x_tile_size * y_tile_size;
> +	tiles_per_line = line_size / x_tile_size;
> +	bpp = sizeof(uint32_t);
> +
> +	tile_n = tiled_pos / tile_size;
> +	tile_off = tiled_pos % tile_size;
> +
> +	y_tile_off = tile_off / x_tile_size;
> +	x_tile_off = tile_off % x_tile_size;
> +
> +	x_tile_n = tile_n % tiles_per_line;
> +	y_tile_n = tile_n / tiles_per_line;
> +
> +	*x = (x_tile_n * x_tile_size + x_tile_off) / bpp;
> +	*y = y_tile_n * y_tile_size + y_tile_off;
> +}
> +
> +static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
> +			       uint32_t color)
> +{
> +	uint32_t *ptr;
> +	int x, y, pos;
> +	uint32_t tiling, swizzle;
> +
> +	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
> +		       I915_GEM_DOMAIN_CPU);
> +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> +
> +	ptr = gem_mmap__cpu(fd, buf->handle, 0, buf->size, 0);
> +	igt_assert(ptr);
> +
> +	for (y = rect->y; y < rect->y + rect->h; y++) {
> +		for (x = rect->x; x < rect->x + rect->w; x++) {
> +			if (tiling)
> +				pos = linear_x_y_to_tiled_pos(x, y, buf->stride,
> +							      swizzle);
> +			else
> +				pos = (y * buf->stride / sizeof(uint32_t)) + x;
> +			ptr[pos] = color;
> +		}
> +	}
> +
> +	gem_sw_finish(fd, buf->handle);
> +
> +	igt_assert(munmap(ptr, buf->size) == 0);
> +}
> +
> +static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
> +			       uint32_t color)
> +{
> +	uint32_t *ptr;
> +	int x, y;
> +
> +	ptr = gem_mmap__gtt(fd, buf->handle, buf->size,
> +			    PROT_READ | PROT_WRITE);
> +	igt_assert(ptr);
> +
> +	for (y = rect->y; y < rect->y + rect->h; y++) {
> +		int line_begin = y * buf->stride / sizeof(uint32_t);
> +		for (x = rect->x; x < rect->x + rect->w; x++)
> +			ptr[line_begin + x] = color;
> +	}
> +
> +	igt_assert(munmap(ptr, buf->size) == 0);
> +}
> +
> +static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
> +				     struct rect *rect, uint32_t color)
> +{
> +	uint32_t tmp[rect->w];
> +	int i, y, offset, bpp;
> +
> +	bpp = sizeof(uint32_t);
> +
> +	for (i = 0; i < rect->w; i++)
> +		tmp[i] = color;
> +
> +	for (y = rect->y; y < rect->y + rect->h; y++) {
> +		offset = (y * buf->stride) + (rect->x * bpp);
> +		gem_write(fd, buf->handle, offset, tmp, rect->w * bpp);
> +	}
> +}
> +
> +static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
> +				   struct rect *rect, uint32_t color,
> +				   uint32_t swizzle)
> +{
> +	int i;
> +	int tiled_pos, bpp, x, y;
> +	uint32_t tmp[1024];
> +	int tmp_used = 0, tmp_size = ARRAY_SIZE(tmp);
> +	bool flush_tmp = false;
> +	int tmp_start_pos = 0;
> +
> +	bpp = sizeof(uint32_t);
> +
> +	/* Instead of doing one pwrite per pixel, we try to group the maximum
> +	 * amount of consecutive pixels we can in a single pwrite: that's why we
> +	 * use the "tmp" variables. */
> +	for (i = 0; i < tmp_size; i++)
> +		tmp[i] = color;
> +
> +	for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += bpp) {
> +		tiled_pos_to_x_y_linear(tiled_pos, buf->stride, swizzle, &x, &y);
> +
> +		if (x >= rect->x && x < rect->x + rect->w &&
> +		    y >= rect->y && y < rect->y + rect->h) {
> +			if (tmp_used == 0)
> +				tmp_start_pos = tiled_pos;
> +			tmp_used++;
> +		} else {
> +			flush_tmp = true;
> +		}
> +
> +		if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0)) {
> +			gem_write(fd, buf->handle, tmp_start_pos, tmp,
> +				  tmp_used * bpp);
> +			flush_tmp = false;
> +			tmp_used = 0;
> +		}
> +	}
> +}
> +
> +static void draw_rect_pwrite(int fd, struct buf_data *buf,
> +			     struct rect *rect, uint32_t color)
> +{
> +	uint32_t tiling, swizzle;
> +
> +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> +
> +	if (tiling)
> +		draw_rect_pwrite_tiled(fd, buf, rect, color, swizzle);
> +	else
> +		draw_rect_pwrite_untiled(fd, buf, rect, color);
> +}
> +
> +static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
> +			  struct buf_data *buf, struct rect *rect,
> +			  uint32_t color)
> +{
> +	drm_intel_bo *dst;
> +	struct intel_batchbuffer *batch;
> +	int blt_cmd_len, blt_cmd_tiling;
> +	uint32_t devid = intel_get_drm_devid(fd);
> +	int gen = intel_gen(devid);
> +	uint32_t tiling, swizzle;
> +	int pitch;
> +
> +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> +
> +	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
> +	igt_assert(dst);
> +
> +	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
> +	igt_assert(batch);
> +
> +	blt_cmd_len = (gen >= 8) ?  0x5 : 0x4;
> +	blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
> +	pitch = (tiling) ? buf->stride / 4 : buf->stride;
> +
> +	BEGIN_BATCH(6, 1);

This breaks on gen8 because there the relocations are 2 dwords. You need
to use the magic macros for that.

> +	OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
> +		  XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
> +	OUT_BATCH((3 << 24) | (0xF0 << 16) | pitch);
> +	OUT_BATCH((rect->y << 16) | rect->x);
> +	OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
> +	if (tiling)
> +		OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
> +	else
> +		OUT_RELOC(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
> +	OUT_BATCH(color);
> +	ADVANCE_BATCH();
> +
> +	intel_batchbuffer_flush(batch);
> +	gem_sync(fd, buf->handle);
> +	intel_batchbuffer_free(batch);
> +}
> +
> +static void draw_rect_render(int fd, struct cmd_data *cmd_data,
> +			     struct buf_data *buf, struct rect *rect,
> +			     uint32_t color)
> +{
> +	drm_intel_bo *src, *dst;
> +	uint32_t devid = intel_get_drm_devid(fd);
> +	igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
> +	struct igt_buf src_buf, dst_buf;
> +	struct intel_batchbuffer *batch;
> +	uint32_t tiling, swizzle;
> +	struct buf_data tmp;
> +
> +	igt_skip_on(!rendercopy);
> +
> +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> +
> +	/* We create a temporary buffer and copy from it using rendercopy. */
> +	tmp.size = rect->w * rect->h * sizeof(uint32_t);
> +	tmp.handle = gem_create(fd, tmp.size);
> +	tmp.stride = rect->w * sizeof(uint32_t);
> +	draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
> +			   color);
> +
> +	src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
> +	igt_assert(src);
> +	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
> +	igt_assert(dst);
> +
> +	src_buf.bo = src;
> +	src_buf.stride = tmp.stride;
> +	src_buf.tiling = I915_TILING_NONE;
> +	src_buf.size = tmp.size;
> +	dst_buf.bo = dst;
> +	dst_buf.stride = buf->stride;
> +	dst_buf.tiling = tiling;
> +	dst_buf.size = buf->size;
> +
> +	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
> +	igt_assert(batch);
> +
> +	rendercopy(batch, cmd_data->context, &src_buf, 0, 0, rect->w, rect->h,
> +		   &dst_buf, rect->x, rect->y);
> +
> +	gem_sync(fd, buf->handle);
> +	intel_batchbuffer_free(batch);
> +	gem_close(fd, tmp.handle);
> +}
> +
> +/**
> + * igt_draw_rect:
> + * @fd: the DRM file descriptor
> + * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
> + *          IGT_DRAW_RENDER
> + * @context: the context, can be NULL if you don't want to think about it
> + * @buf_handle: the handle of the buffer where you're going to draw to
> + * @buf_size: the size of the buffer
> + * @buf_stride: the stride of the buffer
> + * @method: method you're going to use to write to the buffer
> + * @rect_x: horizontal position on the buffer where your rectangle starts
> + * @rect_y: vertical position on the buffer where your rectangle starts
> + * @rect_w: width of the rectangle
> + * @rect_h: height of the rectangle
> + * @color: color of the rectangle
> + *
> + * This function draws a colored rectangle on the destination buffer, allowing
> + * you to specify the method used to draw the rectangle. We assume 32 bit pixels
> + * with 8 bits per color.
> + */
> +void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
> +		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
> +		   enum igt_draw_method method, int rect_x, int rect_y,
> +		   int rect_w, int rect_h, uint32_t color)
> +{
> +	struct cmd_data cmd_data = {
> +		.bufmgr = bufmgr,
> +		.context = context,
> +	};
> +	struct buf_data buf = {
> +		.handle = buf_handle,
> +		.size = buf_size,
> +		.stride = buf_stride,
> +	};
> +	struct rect rect = {
> +		.x = rect_x,
> +		.y = rect_y,
> +		.w = rect_w,
> +		.h = rect_h,
> +	};
> +
> +	switch (method) {
> +	case IGT_DRAW_MMAP_CPU:
> +		draw_rect_mmap_cpu(fd, &buf, &rect, color);
> +		break;
> +	case IGT_DRAW_MMAP_GTT:
> +		draw_rect_mmap_gtt(fd, &buf, &rect, color);
> +		break;
> +	case IGT_DRAW_PWRITE:
> +		draw_rect_pwrite(fd, &buf, &rect, color);
> +		break;
> +	case IGT_DRAW_BLT:
> +		draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
> +		break;
> +	case IGT_DRAW_RENDER:
> +		draw_rect_render(fd, &cmd_data, &buf, &rect, color);
> +		break;
> +	default:
> +		igt_assert(false);
> +		break;
> +	}
> +}
> +
> +/**
> + * igt_draw_rect_fb:
> + *
> + * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
> + * of manually providing its details. See igt_draw_rect.
> + */
> +void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
> +		      drm_intel_context *context, struct igt_fb *fb,
> +		      enum igt_draw_method method, int rect_x, int rect_y,
> +		      int rect_w, int rect_h, uint32_t color)
> +{
> +	igt_draw_rect(fd, bufmgr, context, fb->gem_handle, fb->size, fb->stride,
> +		      method, rect_x, rect_y, rect_w, rect_h, color);
> +}
> +
> +/**
> + * igt_draw_fill_fb:
> + * @fd: the DRM file descriptor
> + * @fb: the FB that is going to be filled
> + * @color: the color you're going to paint it
> + *
> + * This function just paints an igt_fb using the provided color. It assumes 32
> + * bit pixels with 8 bit colors.
> + */
> +void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
> +{
> +	igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
> +			 0, 0, fb->width, fb->height, color);
> +}
> diff --git a/lib/igt_draw.h b/lib/igt_draw.h
> new file mode 100644
> index 0000000..399e17c
> --- /dev/null
> +++ b/lib/igt_draw.h
> @@ -0,0 +1,54 @@
> +/*
> + * Copyright © 2015 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#ifndef __IGT_DRAW_H__
> +#define __IGT_DRAW_H__
> +
> +#include <intel_bufmgr.h>
> +#include "igt_fb.h"
> +

gtkdoc for this enum would be nice too I think.

> +enum igt_draw_method {
> +	IGT_DRAW_MMAP_CPU,
> +	IGT_DRAW_MMAP_GTT,
> +	IGT_DRAW_PWRITE,
> +	IGT_DRAW_BLT,
> +	IGT_DRAW_RENDER,
> +	IGT_DRAW_METHOD_COUNT,
> +};
> +
> +const char *igt_draw_get_method_name(enum igt_draw_method method);
> +
> +void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
> +		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
> +		   enum igt_draw_method method, int rect_x, int rect_y,
> +		   int rect_w, int rect_h, uint32_t color);
> +
> +void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
> +		      drm_intel_context *context, struct igt_fb *fb,
> +		      enum igt_draw_method method, int rect_x, int rect_y,
> +		      int rect_w, int rect_h, uint32_t color);
> +
> +void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color);
> +
> +#endif /* __IGT_DRAW_H__ */
> diff --git a/lib/tests/.gitignore b/lib/tests/.gitignore
> index a745a23..88f668a 100644
> --- a/lib/tests/.gitignore
> +++ b/lib/tests/.gitignore
> @@ -1,4 +1,5 @@
>  # Please keep sorted alphabetically
> +igt_draw
>  igt_fork_helper
>  igt_invalid_subtest_name
>  igt_list_only
> diff --git a/lib/tests/Makefile.sources b/lib/tests/Makefile.sources
> index ecd73ae..ff66d9d 100644
> --- a/lib/tests/Makefile.sources
> +++ b/lib/tests/Makefile.sources
> @@ -1,4 +1,5 @@
>  check_PROGRAMS = \
> +	igt_draw \
>  	igt_no_exit \
>  	igt_no_exit_list_only \
>  	igt_fork_helper \
> diff --git a/lib/tests/igt_draw.c b/lib/tests/igt_draw.c
> new file mode 100644
> index 0000000..1630cc2
> --- /dev/null
> +++ b/lib/tests/igt_draw.c
> @@ -0,0 +1,247 @@
> +/*
> + * Copyright © 2015 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +/* This program tests whether the igt_draw library actually works. */
> +
> +#include "drmtest.h"
> +#include "igt_aux.h"
> +#include "igt_draw.h"
> +#include "igt_debugfs.h"
> +#include "igt_fb.h"
> +#include "igt_kms.h"
> +
> +#define MAX_CONNECTORS 32
> +
> +struct modeset_params {
> +	uint32_t crtc_id;
> +	uint32_t connector_id;
> +	drmModeModeInfoPtr mode;
> +};
> +
> +int drm_fd;
> +drmModeResPtr drm_res;
> +drmModeConnectorPtr drm_connectors[MAX_CONNECTORS];
> +drm_intel_bufmgr *bufmgr;
> +igt_pipe_crc_t *pipe_crc;
> +
> +bool has_method_base_crc = false;
> +igt_crc_t method_base_crc;
> +
> +struct modeset_params ms;
> +
> +static void find_modeset_params(void)
> +{
> +	int i;
> +	uint32_t connector_id = 0, crtc_id;
> +	drmModeModeInfoPtr mode = NULL;
> +
> +	for (i = 0; i < drm_res->count_connectors; i++) {
> +		drmModeConnectorPtr c = drm_connectors[i];
> +
> +		if (c->count_modes) {
> +			connector_id = c->connector_id;
> +			mode = &c->modes[0];
> +			break;
> +		}
> +	}
> +	igt_require(connector_id);
> +
> +	crtc_id = drm_res->crtcs[0];
> +	igt_assert(crtc_id);
> +	igt_assert(mode);
> +
> +	ms.connector_id = connector_id;
> +	ms.crtc_id = crtc_id;
> +	ms.mode = mode;
> +
> +}
> +
> +static void get_method_crc(enum igt_draw_method method, uint64_t tiling,
> +			   igt_crc_t *crc)
> +{
> +	struct igt_fb fb;
> +	int rc;
> +
> +	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
> +		      DRM_FORMAT_XRGB8888, tiling, &fb);
> +	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
> +			 0, 0, fb.width, fb.height, 0xFF);
> +
> +	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
> +			 fb.width / 4, fb.height / 4,
> +			 fb.width / 2, fb.height / 2, 0xFF00);
> +	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
> +			 fb.width / 8, fb.height / 8,
> +			 fb.width / 4, fb.height / 4, 0xFF0000);
> +	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
> +			 fb.width / 2, fb.height / 2,
> +			 fb.width / 3, fb.height / 3, 0xFF00FF);
> +
> +	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
> +			    &ms.connector_id, 1, ms.mode);
> +	igt_assert(rc == 0);
> +
> +	igt_debug_wait_for_keypress("crc");
> +	igt_pipe_crc_collect_crc(pipe_crc, crc);

Should we just move this igt_debug_wait_for_keypress into
igt_pipe_crc_collect_crc?

> +
> +	kmstest_unset_all_crtcs(drm_fd, drm_res);
> +	igt_remove_fb(drm_fd, &fb);
> +}
> +
> +static void draw_method_subtest(enum igt_draw_method method, uint64_t tiling)
> +{
> +	igt_crc_t crc;
> +
> +	kmstest_unset_all_crtcs(drm_fd, drm_res);
> +
> +	find_modeset_params();
> +
> +	/* Use IGT_DRAW_MMAP_GTT on an untiled buffer as the parameter for
> +	 * comparison. Cache the value so we don't recompute it for every single
> +	 * subtest. */
> +	if (!has_method_base_crc) {
> +		get_method_crc(IGT_DRAW_MMAP_GTT, LOCAL_DRM_FORMAT_MOD_NONE,
> +			       &method_base_crc);
> +		has_method_base_crc = true;
> +	}
> +
> +	get_method_crc(method, tiling, &crc);
> +	igt_assert_crc_equal(&crc, &method_base_crc);
> +}
> +
> +static void get_fill_crc(uint64_t tiling, igt_crc_t *crc)
> +{
> +	struct igt_fb fb;
> +	int rc;
> +
> +	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
> +		      DRM_FORMAT_XRGB8888, tiling, &fb);
> +
> +	igt_draw_fill_fb(drm_fd, &fb, 0xFF);
> +
> +	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
> +			    &ms.connector_id, 1, ms.mode);
> +	igt_assert(rc == 0);
> +
> +	igt_debug_wait_for_keypress("crc");
> +	igt_pipe_crc_collect_crc(pipe_crc, crc);
> +
> +	kmstest_unset_all_crtcs(drm_fd, drm_res);
> +	igt_remove_fb(drm_fd, &fb);
> +}
> +
> +static void fill_fb_subtest(void)
> +{
> +	int rc;
> +	struct igt_fb fb;
> +	igt_crc_t base_crc, crc;
> +
> +	kmstest_unset_all_crtcs(drm_fd, drm_res);
> +
> +	find_modeset_params();
> +
> +	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
> +		      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb);
> +
> +	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, IGT_DRAW_MMAP_GTT,
> +			 0, 0, fb.width, fb.height, 0xFF);
> +
> +	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
> +			    &ms.connector_id, 1, ms.mode);
> +	igt_assert(rc == 0);
> +
> +	igt_debug_wait_for_keypress("crc");
> +	igt_pipe_crc_collect_crc(pipe_crc, &base_crc);
> +
> +	get_fill_crc(LOCAL_DRM_FORMAT_MOD_NONE, &crc);
> +	igt_assert_crc_equal(&crc, &base_crc);
> +
> +	get_fill_crc(LOCAL_I915_FORMAT_MOD_X_TILED, &crc);
> +	igt_assert_crc_equal(&crc, &base_crc);
> +
> +	kmstest_unset_all_crtcs(drm_fd, drm_res);
> +	igt_remove_fb(drm_fd, &fb);
> +}
> +
> +static void setup_environment(void)
> +{
> +	int i;
> +
> +	drm_fd = drm_open_any_master();
> +	igt_require(drm_fd >= 0);
> +
> +	drm_res = drmModeGetResources(drm_fd);
> +	igt_assert(drm_res->count_connectors <= MAX_CONNECTORS);
> +
> +	for (i = 0; i < drm_res->count_connectors; i++)
> +		drm_connectors[i] = drmModeGetConnector(drm_fd,
> +							drm_res->connectors[i]);
> +
> +	kmstest_set_vt_graphics_mode();
> +
> +	bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
> +	igt_assert(bufmgr);
> +	drm_intel_bufmgr_gem_enable_reuse(bufmgr);
> +
> +	pipe_crc = igt_pipe_crc_new(0, INTEL_PIPE_CRC_SOURCE_AUTO);
> +}
> +
> +static void teardown_environment(void)
> +{
> +	int i;
> +
> +	igt_pipe_crc_free(pipe_crc);
> +
> +	drm_intel_bufmgr_destroy(bufmgr);
> +
> +	for (i = 0; i < drm_res->count_connectors; i++)
> +		drmModeFreeConnector(drm_connectors[i]);
> +
> +	drmModeFreeResources(drm_res);
> +	close(drm_fd);
> +}
> +
> +igt_main
> +{
> +	enum igt_draw_method method;
> +
> +	igt_fixture
> +		setup_environment();
> +
> +	for (method = 0; method < IGT_DRAW_METHOD_COUNT; method++) {
> +		igt_subtest_f("draw-method-%s-untiled",
> +			      igt_draw_get_method_name(method))
> +			draw_method_subtest(method, LOCAL_DRM_FORMAT_MOD_NONE);
> +		igt_subtest_f("draw-method-%s-tiled",
> +			      igt_draw_get_method_name(method))
> +			draw_method_subtest(method,
> +					    LOCAL_I915_FORMAT_MOD_X_TILED);
> +	}
> +
> +	igt_subtest("fill-fb")
> +		fill_fb_subtest();
> +
> +	igt_fixture
> +		teardown_environment();
> +}
> -- 
> 2.1.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-03-26 10:19   ` Daniel Vetter
@ 2015-03-30 19:45     ` Paulo Zanoni
  2015-03-31 13:07       ` Daniel Vetter
  0 siblings, 1 reply; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-30 19:45 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, Paulo Zanoni

2015-03-26 7:19 GMT-03:00 Daniel Vetter <daniel@ffwll.ch>:
> On Wed, Mar 25, 2015 at 06:50:39PM -0300, Paulo Zanoni wrote:
>> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
>>
>> For all those IGT tests that need an easy way to draw rectangles on
>> buffers using different methods. Current planned users: FBC and PSR
>> CRC tests.
>>
>> There is also a lib/tests/igt_draw program to check if the library is
>> sane.
>
> We need to move that to tests/igt_draw. The testcase in lib/tests/* get
> run with make check, which must be possible as non-root on a non-intel
> (build) machine. If you need an gpu to run your test it must be in tests/*
> as a normal igt kernel test.
>
> Wrt the library itself I'm unsure about the explicit tiling/swizzling.
> Your current code only works on gen5-8 and maintaining a full-blown
> swizzle/tiling library is real work, and means some of the tests can't be
> converted to this.

This would just be a problem for the tests that use it, and no test is
using it yet. This is just for the cases where you want to use the CPU
to write into tiled buffers.

If we start using this in a test, then we need to properly test all
the affected platforms. I have some local FBC tests that use it -
which I was going to submit after getting feedback on this lib -, and
I don't think we'll end needing to run these tests on the older
platforms.


> We do have all the tiling modes encoded in the tiling
> tests though, so if you have a lot of time it might be useful to extract
> tiling helpers into the igt library which work on all generations.

Can you please be more precise here? Where exactly should I look?

>
> I think we should at least have a fallback mode which allows us to fill an
> entire buffer completely (i.e. not just the hxw area) and treat it as
> untiled.

That is not the goal of the library. Still, if we ever need this
function, it would be easy to add.

>
> More comments below.

More below too :)

> -Daniel
>
>>
>> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
>> ---
>>  lib/Makefile.sources       |   2 +
>>  lib/igt_draw.c             | 467 +++++++++++++++++++++++++++++++++++++++++++++
>>  lib/igt_draw.h             |  54 ++++++
>>  lib/tests/.gitignore       |   1 +
>>  lib/tests/Makefile.sources |   1 +
>>  lib/tests/igt_draw.c       | 247 ++++++++++++++++++++++++
>>  6 files changed, 772 insertions(+)
>>  create mode 100644 lib/igt_draw.c
>>  create mode 100644 lib/igt_draw.h
>>  create mode 100644 lib/tests/igt_draw.c
>>
>> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
>> index 3d93629..85dc321 100644
>> --- a/lib/Makefile.sources
>> +++ b/lib/Makefile.sources
>> @@ -52,6 +52,8 @@ libintel_tools_la_SOURCES =         \
>>       igt_fb.h                \
>>       igt_core.c              \
>>       igt_core.h              \
>> +     igt_draw.c              \
>> +     igt_draw.h              \
>>       $(NULL)
>>
>>  .PHONY: version.h.tmp
>> diff --git a/lib/igt_draw.c b/lib/igt_draw.c
>> new file mode 100644
>> index 0000000..4eb7507
>> --- /dev/null
>> +++ b/lib/igt_draw.c
>> @@ -0,0 +1,467 @@
>> +/*
>> + * Copyright © 2015 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + *
>> + */
>> +
>> +#include <sys/mman.h>
>> +
>> +#include "igt_draw.h"
>> +
>> +#include "drmtest.h"
>> +#include "intel_chipset.h"
>> +#include "igt_core.h"
>> +#include "igt_fb.h"
>> +#include "ioctl_wrappers.h"
>> +
>> +/**
>> + * SECTION:igt_draw
>> + * @short_description: drawing helpers for tests
>> + * @title: i-g-t draw
>> + * @include: igt_draw.h
>> + *
>> + * This library contains some functions for drawing rectangles on buffers using
>> + * the many different drawing methods we have. It also contains some wrappers
>> + * that make the process easier if you have the abstract objects in hand.
>> + *
>> + * All functions assume the buffers are in the XRGB 8:8:8 format.
>> + *
>> + */
>> +
>> +/* Some internal data structures to avoid having to pass tons of parameters
>> + * around everything. */
>> +struct cmd_data {
>> +     drm_intel_bufmgr *bufmgr;
>> +     drm_intel_context *context;
>> +};
>> +
>> +struct buf_data {
>> +     uint32_t handle;
>> +     uint32_t size;
>> +     uint32_t stride;
>> +};
>> +
>> +struct rect {
>> +     int x;
>> +     int y;
>> +     int w;
>> +     int h;
>> +};
>> +
>> +const char *igt_draw_get_method_name(enum igt_draw_method method)
>> +{
>> +     switch (method) {
>> +     case IGT_DRAW_MMAP_CPU:
>> +             return "mmap-cpu";
>> +     case IGT_DRAW_MMAP_GTT:
>> +             return "mmap-gtt";
>> +     case IGT_DRAW_PWRITE:
>> +             return "pwrite";
>> +     case IGT_DRAW_BLT:
>> +             return "blt";
>> +     case IGT_DRAW_RENDER:
>> +             return "render";
>> +     default:
>> +             igt_assert(false);
>> +     }
>> +}
>> +
>> +static int swizzle_addr(int addr, int swizzle)
>> +{
>> +     int bit6;
>> +
>> +     if (swizzle == I915_BIT_6_SWIZZLE_9_10) {
>> +             bit6 = ((addr >> 6) & 1) ^ ((addr >> 9) & 1) ^
>> +                    ((addr >> 10) & 1);
>> +             addr &= ~(1 << 6);
>> +             addr |= (bit6 << 6);
>> +     }
>> +
>> +     return addr;
>> +}
>> +
>> +/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
>> + * if you need to. */
>> +static int linear_x_y_to_tiled_pos(int x, int y, uint32_t stride, int swizzle)
>> +{
>> +     int x_tile_size, y_tile_size;
>> +     int x_tile_n, y_tile_n, x_tile_off, y_tile_off;
>> +     int line_size, tile_size;
>> +     int tile_n, tile_off;
>> +     int tiled_pos, tiles_per_line;
>> +     int bpp;
>> +
>> +     line_size = stride;
>> +     x_tile_size = 512;
>> +     y_tile_size = 8;
>> +     tile_size = x_tile_size * y_tile_size;
>> +     tiles_per_line = line_size / x_tile_size;
>> +     bpp = sizeof(uint32_t);
>> +
>> +     y_tile_n = y / y_tile_size;
>> +     y_tile_off = y % y_tile_size;
>> +
>> +     x_tile_n = (x * bpp) / x_tile_size;
>> +     x_tile_off = (x * bpp) % x_tile_size;
>> +
>> +     tile_n = y_tile_n * tiles_per_line + x_tile_n;
>> +     tile_off = y_tile_off * x_tile_size + x_tile_off;
>> +     tiled_pos = tile_n * tile_size + tile_off;
>> +
>> +     tiled_pos = swizzle_addr(tiled_pos, swizzle);
>> +
>> +     return tiled_pos / bpp;
>> +}
>> +
>> +/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
>> + * if you need to. */
>> +static void tiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
>> +                                 int swizzle, int *x, int *y)
>> +{
>> +     int tile_n, tile_off, tiles_per_line, line_size;
>> +     int x_tile_off, y_tile_off;
>> +     int x_tile_n, y_tile_n;
>> +     int x_tile_size, y_tile_size, tile_size;
>> +     int bpp;
>> +
>> +     tiled_pos = swizzle_addr(tiled_pos, swizzle);
>> +
>> +     line_size = stride;
>> +     x_tile_size = 512;
>> +     y_tile_size = 8;
>> +     tile_size = x_tile_size * y_tile_size;
>> +     tiles_per_line = line_size / x_tile_size;
>> +     bpp = sizeof(uint32_t);
>> +
>> +     tile_n = tiled_pos / tile_size;
>> +     tile_off = tiled_pos % tile_size;
>> +
>> +     y_tile_off = tile_off / x_tile_size;
>> +     x_tile_off = tile_off % x_tile_size;
>> +
>> +     x_tile_n = tile_n % tiles_per_line;
>> +     y_tile_n = tile_n / tiles_per_line;
>> +
>> +     *x = (x_tile_n * x_tile_size + x_tile_off) / bpp;
>> +     *y = y_tile_n * y_tile_size + y_tile_off;
>> +}
>> +
>> +static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
>> +                            uint32_t color)
>> +{
>> +     uint32_t *ptr;
>> +     int x, y, pos;
>> +     uint32_t tiling, swizzle;
>> +
>> +     gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
>> +                    I915_GEM_DOMAIN_CPU);
>> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
>> +
>> +     ptr = gem_mmap__cpu(fd, buf->handle, 0, buf->size, 0);
>> +     igt_assert(ptr);
>> +
>> +     for (y = rect->y; y < rect->y + rect->h; y++) {
>> +             for (x = rect->x; x < rect->x + rect->w; x++) {
>> +                     if (tiling)
>> +                             pos = linear_x_y_to_tiled_pos(x, y, buf->stride,
>> +                                                           swizzle);
>> +                     else
>> +                             pos = (y * buf->stride / sizeof(uint32_t)) + x;
>> +                     ptr[pos] = color;
>> +             }
>> +     }
>> +
>> +     gem_sw_finish(fd, buf->handle);
>> +
>> +     igt_assert(munmap(ptr, buf->size) == 0);
>> +}
>> +
>> +static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
>> +                            uint32_t color)
>> +{
>> +     uint32_t *ptr;
>> +     int x, y;
>> +
>> +     ptr = gem_mmap__gtt(fd, buf->handle, buf->size,
>> +                         PROT_READ | PROT_WRITE);
>> +     igt_assert(ptr);
>> +
>> +     for (y = rect->y; y < rect->y + rect->h; y++) {
>> +             int line_begin = y * buf->stride / sizeof(uint32_t);
>> +             for (x = rect->x; x < rect->x + rect->w; x++)
>> +                     ptr[line_begin + x] = color;
>> +     }
>> +
>> +     igt_assert(munmap(ptr, buf->size) == 0);
>> +}
>> +
>> +static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
>> +                                  struct rect *rect, uint32_t color)
>> +{
>> +     uint32_t tmp[rect->w];
>> +     int i, y, offset, bpp;
>> +
>> +     bpp = sizeof(uint32_t);
>> +
>> +     for (i = 0; i < rect->w; i++)
>> +             tmp[i] = color;
>> +
>> +     for (y = rect->y; y < rect->y + rect->h; y++) {
>> +             offset = (y * buf->stride) + (rect->x * bpp);
>> +             gem_write(fd, buf->handle, offset, tmp, rect->w * bpp);
>> +     }
>> +}
>> +
>> +static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
>> +                                struct rect *rect, uint32_t color,
>> +                                uint32_t swizzle)
>> +{
>> +     int i;
>> +     int tiled_pos, bpp, x, y;
>> +     uint32_t tmp[1024];
>> +     int tmp_used = 0, tmp_size = ARRAY_SIZE(tmp);
>> +     bool flush_tmp = false;
>> +     int tmp_start_pos = 0;
>> +
>> +     bpp = sizeof(uint32_t);
>> +
>> +     /* Instead of doing one pwrite per pixel, we try to group the maximum
>> +      * amount of consecutive pixels we can in a single pwrite: that's why we
>> +      * use the "tmp" variables. */
>> +     for (i = 0; i < tmp_size; i++)
>> +             tmp[i] = color;
>> +
>> +     for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += bpp) {
>> +             tiled_pos_to_x_y_linear(tiled_pos, buf->stride, swizzle, &x, &y);
>> +
>> +             if (x >= rect->x && x < rect->x + rect->w &&
>> +                 y >= rect->y && y < rect->y + rect->h) {
>> +                     if (tmp_used == 0)
>> +                             tmp_start_pos = tiled_pos;
>> +                     tmp_used++;
>> +             } else {
>> +                     flush_tmp = true;
>> +             }
>> +
>> +             if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0)) {
>> +                     gem_write(fd, buf->handle, tmp_start_pos, tmp,
>> +                               tmp_used * bpp);
>> +                     flush_tmp = false;
>> +                     tmp_used = 0;
>> +             }
>> +     }
>> +}
>> +
>> +static void draw_rect_pwrite(int fd, struct buf_data *buf,
>> +                          struct rect *rect, uint32_t color)
>> +{
>> +     uint32_t tiling, swizzle;
>> +
>> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
>> +
>> +     if (tiling)
>> +             draw_rect_pwrite_tiled(fd, buf, rect, color, swizzle);
>> +     else
>> +             draw_rect_pwrite_untiled(fd, buf, rect, color);
>> +}
>> +
>> +static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
>> +                       struct buf_data *buf, struct rect *rect,
>> +                       uint32_t color)
>> +{
>> +     drm_intel_bo *dst;
>> +     struct intel_batchbuffer *batch;
>> +     int blt_cmd_len, blt_cmd_tiling;
>> +     uint32_t devid = intel_get_drm_devid(fd);
>> +     int gen = intel_gen(devid);
>> +     uint32_t tiling, swizzle;
>> +     int pitch;
>> +
>> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
>> +
>> +     dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
>> +     igt_assert(dst);
>> +
>> +     batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
>> +     igt_assert(batch);
>> +
>> +     blt_cmd_len = (gen >= 8) ?  0x5 : 0x4;
>> +     blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
>> +     pitch = (tiling) ? buf->stride / 4 : buf->stride;
>> +
>> +     BEGIN_BATCH(6, 1);
>
> This breaks on gen8 because there the relocations are 2 dwords. You need
> to use the magic macros for that.
>

Please read the code again. I actually developed and tested everything
on gen8 :)

>> +     OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
>> +               XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
>> +     OUT_BATCH((3 << 24) | (0xF0 << 16) | pitch);
>> +     OUT_BATCH((rect->y << 16) | rect->x);
>> +     OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
>> +     if (tiling)
>> +             OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
>> +     else
>> +             OUT_RELOC(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
>> +     OUT_BATCH(color);
>> +     ADVANCE_BATCH();
>> +
>> +     intel_batchbuffer_flush(batch);
>> +     gem_sync(fd, buf->handle);
>> +     intel_batchbuffer_free(batch);
>> +}
>> +
>> +static void draw_rect_render(int fd, struct cmd_data *cmd_data,
>> +                          struct buf_data *buf, struct rect *rect,
>> +                          uint32_t color)
>> +{
>> +     drm_intel_bo *src, *dst;
>> +     uint32_t devid = intel_get_drm_devid(fd);
>> +     igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
>> +     struct igt_buf src_buf, dst_buf;
>> +     struct intel_batchbuffer *batch;
>> +     uint32_t tiling, swizzle;
>> +     struct buf_data tmp;
>> +
>> +     igt_skip_on(!rendercopy);
>> +
>> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
>> +
>> +     /* We create a temporary buffer and copy from it using rendercopy. */
>> +     tmp.size = rect->w * rect->h * sizeof(uint32_t);
>> +     tmp.handle = gem_create(fd, tmp.size);
>> +     tmp.stride = rect->w * sizeof(uint32_t);
>> +     draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
>> +                        color);
>> +
>> +     src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
>> +     igt_assert(src);
>> +     dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
>> +     igt_assert(dst);
>> +
>> +     src_buf.bo = src;
>> +     src_buf.stride = tmp.stride;
>> +     src_buf.tiling = I915_TILING_NONE;
>> +     src_buf.size = tmp.size;
>> +     dst_buf.bo = dst;
>> +     dst_buf.stride = buf->stride;
>> +     dst_buf.tiling = tiling;
>> +     dst_buf.size = buf->size;
>> +
>> +     batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
>> +     igt_assert(batch);
>> +
>> +     rendercopy(batch, cmd_data->context, &src_buf, 0, 0, rect->w, rect->h,
>> +                &dst_buf, rect->x, rect->y);
>> +
>> +     gem_sync(fd, buf->handle);
>> +     intel_batchbuffer_free(batch);
>> +     gem_close(fd, tmp.handle);
>> +}
>> +
>> +/**
>> + * igt_draw_rect:
>> + * @fd: the DRM file descriptor
>> + * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
>> + *          IGT_DRAW_RENDER
>> + * @context: the context, can be NULL if you don't want to think about it
>> + * @buf_handle: the handle of the buffer where you're going to draw to
>> + * @buf_size: the size of the buffer
>> + * @buf_stride: the stride of the buffer
>> + * @method: method you're going to use to write to the buffer
>> + * @rect_x: horizontal position on the buffer where your rectangle starts
>> + * @rect_y: vertical position on the buffer where your rectangle starts
>> + * @rect_w: width of the rectangle
>> + * @rect_h: height of the rectangle
>> + * @color: color of the rectangle
>> + *
>> + * This function draws a colored rectangle on the destination buffer, allowing
>> + * you to specify the method used to draw the rectangle. We assume 32 bit pixels
>> + * with 8 bits per color.
>> + */
>> +void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
>> +                uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
>> +                enum igt_draw_method method, int rect_x, int rect_y,
>> +                int rect_w, int rect_h, uint32_t color)
>> +{
>> +     struct cmd_data cmd_data = {
>> +             .bufmgr = bufmgr,
>> +             .context = context,
>> +     };
>> +     struct buf_data buf = {
>> +             .handle = buf_handle,
>> +             .size = buf_size,
>> +             .stride = buf_stride,
>> +     };
>> +     struct rect rect = {
>> +             .x = rect_x,
>> +             .y = rect_y,
>> +             .w = rect_w,
>> +             .h = rect_h,
>> +     };
>> +
>> +     switch (method) {
>> +     case IGT_DRAW_MMAP_CPU:
>> +             draw_rect_mmap_cpu(fd, &buf, &rect, color);
>> +             break;
>> +     case IGT_DRAW_MMAP_GTT:
>> +             draw_rect_mmap_gtt(fd, &buf, &rect, color);
>> +             break;
>> +     case IGT_DRAW_PWRITE:
>> +             draw_rect_pwrite(fd, &buf, &rect, color);
>> +             break;
>> +     case IGT_DRAW_BLT:
>> +             draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
>> +             break;
>> +     case IGT_DRAW_RENDER:
>> +             draw_rect_render(fd, &cmd_data, &buf, &rect, color);
>> +             break;
>> +     default:
>> +             igt_assert(false);
>> +             break;
>> +     }
>> +}
>> +
>> +/**
>> + * igt_draw_rect_fb:
>> + *
>> + * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
>> + * of manually providing its details. See igt_draw_rect.
>> + */
>> +void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
>> +                   drm_intel_context *context, struct igt_fb *fb,
>> +                   enum igt_draw_method method, int rect_x, int rect_y,
>> +                   int rect_w, int rect_h, uint32_t color)
>> +{
>> +     igt_draw_rect(fd, bufmgr, context, fb->gem_handle, fb->size, fb->stride,
>> +                   method, rect_x, rect_y, rect_w, rect_h, color);
>> +}
>> +
>> +/**
>> + * igt_draw_fill_fb:
>> + * @fd: the DRM file descriptor
>> + * @fb: the FB that is going to be filled
>> + * @color: the color you're going to paint it
>> + *
>> + * This function just paints an igt_fb using the provided color. It assumes 32
>> + * bit pixels with 8 bit colors.
>> + */
>> +void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
>> +{
>> +     igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
>> +                      0, 0, fb->width, fb->height, color);
>> +}
>> diff --git a/lib/igt_draw.h b/lib/igt_draw.h
>> new file mode 100644
>> index 0000000..399e17c
>> --- /dev/null
>> +++ b/lib/igt_draw.h
>> @@ -0,0 +1,54 @@
>> +/*
>> + * Copyright © 2015 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + *
>> + */
>> +
>> +#ifndef __IGT_DRAW_H__
>> +#define __IGT_DRAW_H__
>> +
>> +#include <intel_bufmgr.h>
>> +#include "igt_fb.h"
>> +
>
> gtkdoc for this enum would be nice too I think.

Ok.


>
>> +enum igt_draw_method {
>> +     IGT_DRAW_MMAP_CPU,
>> +     IGT_DRAW_MMAP_GTT,
>> +     IGT_DRAW_PWRITE,
>> +     IGT_DRAW_BLT,
>> +     IGT_DRAW_RENDER,
>> +     IGT_DRAW_METHOD_COUNT,
>> +};
>> +
>> +const char *igt_draw_get_method_name(enum igt_draw_method method);
>> +
>> +void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
>> +                uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
>> +                enum igt_draw_method method, int rect_x, int rect_y,
>> +                int rect_w, int rect_h, uint32_t color);
>> +
>> +void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
>> +                   drm_intel_context *context, struct igt_fb *fb,
>> +                   enum igt_draw_method method, int rect_x, int rect_y,
>> +                   int rect_w, int rect_h, uint32_t color);
>> +
>> +void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color);
>> +
>> +#endif /* __IGT_DRAW_H__ */
>> diff --git a/lib/tests/.gitignore b/lib/tests/.gitignore
>> index a745a23..88f668a 100644
>> --- a/lib/tests/.gitignore
>> +++ b/lib/tests/.gitignore
>> @@ -1,4 +1,5 @@
>>  # Please keep sorted alphabetically
>> +igt_draw
>>  igt_fork_helper
>>  igt_invalid_subtest_name
>>  igt_list_only
>> diff --git a/lib/tests/Makefile.sources b/lib/tests/Makefile.sources
>> index ecd73ae..ff66d9d 100644
>> --- a/lib/tests/Makefile.sources
>> +++ b/lib/tests/Makefile.sources
>> @@ -1,4 +1,5 @@
>>  check_PROGRAMS = \
>> +     igt_draw \
>>       igt_no_exit \
>>       igt_no_exit_list_only \
>>       igt_fork_helper \
>> diff --git a/lib/tests/igt_draw.c b/lib/tests/igt_draw.c
>> new file mode 100644
>> index 0000000..1630cc2
>> --- /dev/null
>> +++ b/lib/tests/igt_draw.c
>> @@ -0,0 +1,247 @@
>> +/*
>> + * Copyright © 2015 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + *
>> + */
>> +
>> +/* This program tests whether the igt_draw library actually works. */
>> +
>> +#include "drmtest.h"
>> +#include "igt_aux.h"
>> +#include "igt_draw.h"
>> +#include "igt_debugfs.h"
>> +#include "igt_fb.h"
>> +#include "igt_kms.h"
>> +
>> +#define MAX_CONNECTORS 32
>> +
>> +struct modeset_params {
>> +     uint32_t crtc_id;
>> +     uint32_t connector_id;
>> +     drmModeModeInfoPtr mode;
>> +};
>> +
>> +int drm_fd;
>> +drmModeResPtr drm_res;
>> +drmModeConnectorPtr drm_connectors[MAX_CONNECTORS];
>> +drm_intel_bufmgr *bufmgr;
>> +igt_pipe_crc_t *pipe_crc;
>> +
>> +bool has_method_base_crc = false;
>> +igt_crc_t method_base_crc;
>> +
>> +struct modeset_params ms;
>> +
>> +static void find_modeset_params(void)
>> +{
>> +     int i;
>> +     uint32_t connector_id = 0, crtc_id;
>> +     drmModeModeInfoPtr mode = NULL;
>> +
>> +     for (i = 0; i < drm_res->count_connectors; i++) {
>> +             drmModeConnectorPtr c = drm_connectors[i];
>> +
>> +             if (c->count_modes) {
>> +                     connector_id = c->connector_id;
>> +                     mode = &c->modes[0];
>> +                     break;
>> +             }
>> +     }
>> +     igt_require(connector_id);
>> +
>> +     crtc_id = drm_res->crtcs[0];
>> +     igt_assert(crtc_id);
>> +     igt_assert(mode);
>> +
>> +     ms.connector_id = connector_id;
>> +     ms.crtc_id = crtc_id;
>> +     ms.mode = mode;
>> +
>> +}
>> +
>> +static void get_method_crc(enum igt_draw_method method, uint64_t tiling,
>> +                        igt_crc_t *crc)
>> +{
>> +     struct igt_fb fb;
>> +     int rc;
>> +
>> +     igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
>> +                   DRM_FORMAT_XRGB8888, tiling, &fb);
>> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
>> +                      0, 0, fb.width, fb.height, 0xFF);
>> +
>> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
>> +                      fb.width / 4, fb.height / 4,
>> +                      fb.width / 2, fb.height / 2, 0xFF00);
>> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
>> +                      fb.width / 8, fb.height / 8,
>> +                      fb.width / 4, fb.height / 4, 0xFF0000);
>> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
>> +                      fb.width / 2, fb.height / 2,
>> +                      fb.width / 3, fb.height / 3, 0xFF00FF);
>> +
>> +     rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
>> +                         &ms.connector_id, 1, ms.mode);
>> +     igt_assert(rc == 0);
>> +
>> +     igt_debug_wait_for_keypress("crc");
>> +     igt_pipe_crc_collect_crc(pipe_crc, crc);
>
> Should we just move this igt_debug_wait_for_keypress into
> igt_pipe_crc_collect_crc?

I think I prefer to leave these on the programs because you can then
opt-out of some cases such as when you're getting the reference CRCs.
It doesn't hurt to just add these to the problems, but it can be
annoying if the wait is on the lib and you don't want it.

>
>> +
>> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> +     igt_remove_fb(drm_fd, &fb);
>> +}
>> +
>> +static void draw_method_subtest(enum igt_draw_method method, uint64_t tiling)
>> +{
>> +     igt_crc_t crc;
>> +
>> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> +
>> +     find_modeset_params();
>> +
>> +     /* Use IGT_DRAW_MMAP_GTT on an untiled buffer as the parameter for
>> +      * comparison. Cache the value so we don't recompute it for every single
>> +      * subtest. */
>> +     if (!has_method_base_crc) {
>> +             get_method_crc(IGT_DRAW_MMAP_GTT, LOCAL_DRM_FORMAT_MOD_NONE,
>> +                            &method_base_crc);
>> +             has_method_base_crc = true;
>> +     }
>> +
>> +     get_method_crc(method, tiling, &crc);
>> +     igt_assert_crc_equal(&crc, &method_base_crc);
>> +}
>> +
>> +static void get_fill_crc(uint64_t tiling, igt_crc_t *crc)
>> +{
>> +     struct igt_fb fb;
>> +     int rc;
>> +
>> +     igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
>> +                   DRM_FORMAT_XRGB8888, tiling, &fb);
>> +
>> +     igt_draw_fill_fb(drm_fd, &fb, 0xFF);
>> +
>> +     rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
>> +                         &ms.connector_id, 1, ms.mode);
>> +     igt_assert(rc == 0);
>> +
>> +     igt_debug_wait_for_keypress("crc");
>> +     igt_pipe_crc_collect_crc(pipe_crc, crc);
>> +
>> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> +     igt_remove_fb(drm_fd, &fb);
>> +}
>> +
>> +static void fill_fb_subtest(void)
>> +{
>> +     int rc;
>> +     struct igt_fb fb;
>> +     igt_crc_t base_crc, crc;
>> +
>> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> +
>> +     find_modeset_params();
>> +
>> +     igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
>> +                   DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb);
>> +
>> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, IGT_DRAW_MMAP_GTT,
>> +                      0, 0, fb.width, fb.height, 0xFF);
>> +
>> +     rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
>> +                         &ms.connector_id, 1, ms.mode);
>> +     igt_assert(rc == 0);
>> +
>> +     igt_debug_wait_for_keypress("crc");
>> +     igt_pipe_crc_collect_crc(pipe_crc, &base_crc);
>> +
>> +     get_fill_crc(LOCAL_DRM_FORMAT_MOD_NONE, &crc);
>> +     igt_assert_crc_equal(&crc, &base_crc);
>> +
>> +     get_fill_crc(LOCAL_I915_FORMAT_MOD_X_TILED, &crc);
>> +     igt_assert_crc_equal(&crc, &base_crc);
>> +
>> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> +     igt_remove_fb(drm_fd, &fb);
>> +}
>> +
>> +static void setup_environment(void)
>> +{
>> +     int i;
>> +
>> +     drm_fd = drm_open_any_master();
>> +     igt_require(drm_fd >= 0);
>> +
>> +     drm_res = drmModeGetResources(drm_fd);
>> +     igt_assert(drm_res->count_connectors <= MAX_CONNECTORS);
>> +
>> +     for (i = 0; i < drm_res->count_connectors; i++)
>> +             drm_connectors[i] = drmModeGetConnector(drm_fd,
>> +                                                     drm_res->connectors[i]);
>> +
>> +     kmstest_set_vt_graphics_mode();
>> +
>> +     bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
>> +     igt_assert(bufmgr);
>> +     drm_intel_bufmgr_gem_enable_reuse(bufmgr);
>> +
>> +     pipe_crc = igt_pipe_crc_new(0, INTEL_PIPE_CRC_SOURCE_AUTO);
>> +}
>> +
>> +static void teardown_environment(void)
>> +{
>> +     int i;
>> +
>> +     igt_pipe_crc_free(pipe_crc);
>> +
>> +     drm_intel_bufmgr_destroy(bufmgr);
>> +
>> +     for (i = 0; i < drm_res->count_connectors; i++)
>> +             drmModeFreeConnector(drm_connectors[i]);
>> +
>> +     drmModeFreeResources(drm_res);
>> +     close(drm_fd);
>> +}
>> +
>> +igt_main
>> +{
>> +     enum igt_draw_method method;
>> +
>> +     igt_fixture
>> +             setup_environment();
>> +
>> +     for (method = 0; method < IGT_DRAW_METHOD_COUNT; method++) {
>> +             igt_subtest_f("draw-method-%s-untiled",
>> +                           igt_draw_get_method_name(method))
>> +                     draw_method_subtest(method, LOCAL_DRM_FORMAT_MOD_NONE);
>> +             igt_subtest_f("draw-method-%s-tiled",
>> +                           igt_draw_get_method_name(method))
>> +                     draw_method_subtest(method,
>> +                                         LOCAL_I915_FORMAT_MOD_X_TILED);
>> +     }
>> +
>> +     igt_subtest("fill-fb")
>> +             fill_fb_subtest();
>> +
>> +     igt_fixture
>> +             teardown_environment();
>> +}
>> --
>> 2.1.4
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch



-- 
Paulo Zanoni
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-03-30 19:45     ` Paulo Zanoni
@ 2015-03-31 13:07       ` Daniel Vetter
  2015-03-31 14:03         ` Paulo Zanoni
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2015-03-31 13:07 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development, Paulo Zanoni

On Mon, Mar 30, 2015 at 04:45:49PM -0300, Paulo Zanoni wrote:
> 2015-03-26 7:19 GMT-03:00 Daniel Vetter <daniel@ffwll.ch>:
> > On Wed, Mar 25, 2015 at 06:50:39PM -0300, Paulo Zanoni wrote:
> >> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> >>
> >> For all those IGT tests that need an easy way to draw rectangles on
> >> buffers using different methods. Current planned users: FBC and PSR
> >> CRC tests.
> >>
> >> There is also a lib/tests/igt_draw program to check if the library is
> >> sane.
> >
> > We need to move that to tests/igt_draw. The testcase in lib/tests/* get
> > run with make check, which must be possible as non-root on a non-intel
> > (build) machine. If you need an gpu to run your test it must be in tests/*
> > as a normal igt kernel test.
> >
> > Wrt the library itself I'm unsure about the explicit tiling/swizzling.
> > Your current code only works on gen5-8 and maintaining a full-blown
> > swizzle/tiling library is real work, and means some of the tests can't be
> > converted to this.
> 
> This would just be a problem for the tests that use it, and no test is
> using it yet. This is just for the cases where you want to use the CPU
> to write into tiled buffers.
> 
> If we start using this in a test, then we need to properly test all
> the affected platforms. I have some local FBC tests that use it -
> which I was going to submit after getting feedback on this lib -, and
> I don't think we'll end needing to run these tests on the older
> platforms.
> 
> 
> > We do have all the tiling modes encoded in the tiling
> > tests though, so if you have a lot of time it might be useful to extract
> > tiling helpers into the igt library which work on all generations.
> 
> Can you please be more precise here? Where exactly should I look?

gem_tiled_pread has the full-blown tiling/swizzle logic for all platforms.
This is the one test we have which should work everywhere.

My concern is that by implementing a library which doesn't support
everywhere we havea  bit a split in the testbase which might surprise
people. Imo a library function should work everywhere. If you look at the
code in there compared to yours there's just 2 things missing:
- Variable tile size/height.
- Some of the more crazy swizzle modes.

Also if we have a library which works everywhere we could extend it with
the new fancy gen9+ tiling modes.

> > I think we should at least have a fallback mode which allows us to fill an
> > entire buffer completely (i.e. not just the hxw area) and treat it as
> > untiled.
> 
> That is not the goal of the library. Still, if we ever need this
> function, it would be easy to add.

That was just meant as a fallback for buffers where you don't support the
exact tiling/swizzling mode.
> 
> >
> > More comments below.
> 
> More below too :)
> 
> > -Daniel
> >
> >>
> >> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> >> ---
> >>  lib/Makefile.sources       |   2 +
> >>  lib/igt_draw.c             | 467 +++++++++++++++++++++++++++++++++++++++++++++
> >>  lib/igt_draw.h             |  54 ++++++
> >>  lib/tests/.gitignore       |   1 +
> >>  lib/tests/Makefile.sources |   1 +
> >>  lib/tests/igt_draw.c       | 247 ++++++++++++++++++++++++
> >>  6 files changed, 772 insertions(+)
> >>  create mode 100644 lib/igt_draw.c
> >>  create mode 100644 lib/igt_draw.h
> >>  create mode 100644 lib/tests/igt_draw.c
> >>
> >> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> >> index 3d93629..85dc321 100644
> >> --- a/lib/Makefile.sources
> >> +++ b/lib/Makefile.sources
> >> @@ -52,6 +52,8 @@ libintel_tools_la_SOURCES =         \
> >>       igt_fb.h                \
> >>       igt_core.c              \
> >>       igt_core.h              \
> >> +     igt_draw.c              \
> >> +     igt_draw.h              \
> >>       $(NULL)
> >>
> >>  .PHONY: version.h.tmp
> >> diff --git a/lib/igt_draw.c b/lib/igt_draw.c
> >> new file mode 100644
> >> index 0000000..4eb7507
> >> --- /dev/null
> >> +++ b/lib/igt_draw.c
> >> @@ -0,0 +1,467 @@
> >> +/*
> >> + * Copyright © 2015 Intel Corporation
> >> + *
> >> + * Permission is hereby granted, free of charge, to any person obtaining a
> >> + * copy of this software and associated documentation files (the "Software"),
> >> + * to deal in the Software without restriction, including without limitation
> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> >> + * and/or sell copies of the Software, and to permit persons to whom the
> >> + * Software is furnished to do so, subject to the following conditions:
> >> + *
> >> + * The above copyright notice and this permission notice (including the next
> >> + * paragraph) shall be included in all copies or substantial portions of the
> >> + * Software.
> >> + *
> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> >> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> >> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> >> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> >> + * IN THE SOFTWARE.
> >> + *
> >> + */
> >> +
> >> +#include <sys/mman.h>
> >> +
> >> +#include "igt_draw.h"
> >> +
> >> +#include "drmtest.h"
> >> +#include "intel_chipset.h"
> >> +#include "igt_core.h"
> >> +#include "igt_fb.h"
> >> +#include "ioctl_wrappers.h"
> >> +
> >> +/**
> >> + * SECTION:igt_draw
> >> + * @short_description: drawing helpers for tests
> >> + * @title: i-g-t draw
> >> + * @include: igt_draw.h
> >> + *
> >> + * This library contains some functions for drawing rectangles on buffers using
> >> + * the many different drawing methods we have. It also contains some wrappers
> >> + * that make the process easier if you have the abstract objects in hand.
> >> + *
> >> + * All functions assume the buffers are in the XRGB 8:8:8 format.
> >> + *
> >> + */
> >> +
> >> +/* Some internal data structures to avoid having to pass tons of parameters
> >> + * around everything. */
> >> +struct cmd_data {
> >> +     drm_intel_bufmgr *bufmgr;
> >> +     drm_intel_context *context;
> >> +};
> >> +
> >> +struct buf_data {
> >> +     uint32_t handle;
> >> +     uint32_t size;
> >> +     uint32_t stride;
> >> +};
> >> +
> >> +struct rect {
> >> +     int x;
> >> +     int y;
> >> +     int w;
> >> +     int h;
> >> +};
> >> +
> >> +const char *igt_draw_get_method_name(enum igt_draw_method method)
> >> +{
> >> +     switch (method) {
> >> +     case IGT_DRAW_MMAP_CPU:
> >> +             return "mmap-cpu";
> >> +     case IGT_DRAW_MMAP_GTT:
> >> +             return "mmap-gtt";
> >> +     case IGT_DRAW_PWRITE:
> >> +             return "pwrite";
> >> +     case IGT_DRAW_BLT:
> >> +             return "blt";
> >> +     case IGT_DRAW_RENDER:
> >> +             return "render";
> >> +     default:
> >> +             igt_assert(false);
> >> +     }
> >> +}
> >> +
> >> +static int swizzle_addr(int addr, int swizzle)
> >> +{
> >> +     int bit6;
> >> +
> >> +     if (swizzle == I915_BIT_6_SWIZZLE_9_10) {
> >> +             bit6 = ((addr >> 6) & 1) ^ ((addr >> 9) & 1) ^
> >> +                    ((addr >> 10) & 1);
> >> +             addr &= ~(1 << 6);
> >> +             addr |= (bit6 << 6);
> >> +     }
> >> +
> >> +     return addr;
> >> +}
> >> +
> >> +/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
> >> + * if you need to. */
> >> +static int linear_x_y_to_tiled_pos(int x, int y, uint32_t stride, int swizzle)
> >> +{
> >> +     int x_tile_size, y_tile_size;
> >> +     int x_tile_n, y_tile_n, x_tile_off, y_tile_off;
> >> +     int line_size, tile_size;
> >> +     int tile_n, tile_off;
> >> +     int tiled_pos, tiles_per_line;
> >> +     int bpp;
> >> +
> >> +     line_size = stride;
> >> +     x_tile_size = 512;
> >> +     y_tile_size = 8;
> >> +     tile_size = x_tile_size * y_tile_size;
> >> +     tiles_per_line = line_size / x_tile_size;
> >> +     bpp = sizeof(uint32_t);
> >> +
> >> +     y_tile_n = y / y_tile_size;
> >> +     y_tile_off = y % y_tile_size;
> >> +
> >> +     x_tile_n = (x * bpp) / x_tile_size;
> >> +     x_tile_off = (x * bpp) % x_tile_size;
> >> +
> >> +     tile_n = y_tile_n * tiles_per_line + x_tile_n;
> >> +     tile_off = y_tile_off * x_tile_size + x_tile_off;
> >> +     tiled_pos = tile_n * tile_size + tile_off;
> >> +
> >> +     tiled_pos = swizzle_addr(tiled_pos, swizzle);
> >> +
> >> +     return tiled_pos / bpp;
> >> +}
> >> +
> >> +/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
> >> + * if you need to. */
> >> +static void tiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
> >> +                                 int swizzle, int *x, int *y)
> >> +{
> >> +     int tile_n, tile_off, tiles_per_line, line_size;
> >> +     int x_tile_off, y_tile_off;
> >> +     int x_tile_n, y_tile_n;
> >> +     int x_tile_size, y_tile_size, tile_size;
> >> +     int bpp;
> >> +
> >> +     tiled_pos = swizzle_addr(tiled_pos, swizzle);
> >> +
> >> +     line_size = stride;
> >> +     x_tile_size = 512;
> >> +     y_tile_size = 8;
> >> +     tile_size = x_tile_size * y_tile_size;
> >> +     tiles_per_line = line_size / x_tile_size;
> >> +     bpp = sizeof(uint32_t);
> >> +
> >> +     tile_n = tiled_pos / tile_size;
> >> +     tile_off = tiled_pos % tile_size;
> >> +
> >> +     y_tile_off = tile_off / x_tile_size;
> >> +     x_tile_off = tile_off % x_tile_size;
> >> +
> >> +     x_tile_n = tile_n % tiles_per_line;
> >> +     y_tile_n = tile_n / tiles_per_line;
> >> +
> >> +     *x = (x_tile_n * x_tile_size + x_tile_off) / bpp;
> >> +     *y = y_tile_n * y_tile_size + y_tile_off;
> >> +}
> >> +
> >> +static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
> >> +                            uint32_t color)
> >> +{
> >> +     uint32_t *ptr;
> >> +     int x, y, pos;
> >> +     uint32_t tiling, swizzle;
> >> +
> >> +     gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
> >> +                    I915_GEM_DOMAIN_CPU);
> >> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> >> +
> >> +     ptr = gem_mmap__cpu(fd, buf->handle, 0, buf->size, 0);
> >> +     igt_assert(ptr);
> >> +
> >> +     for (y = rect->y; y < rect->y + rect->h; y++) {
> >> +             for (x = rect->x; x < rect->x + rect->w; x++) {
> >> +                     if (tiling)
> >> +                             pos = linear_x_y_to_tiled_pos(x, y, buf->stride,
> >> +                                                           swizzle);
> >> +                     else
> >> +                             pos = (y * buf->stride / sizeof(uint32_t)) + x;
> >> +                     ptr[pos] = color;
> >> +             }
> >> +     }
> >> +
> >> +     gem_sw_finish(fd, buf->handle);
> >> +
> >> +     igt_assert(munmap(ptr, buf->size) == 0);
> >> +}
> >> +
> >> +static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
> >> +                            uint32_t color)
> >> +{
> >> +     uint32_t *ptr;
> >> +     int x, y;
> >> +
> >> +     ptr = gem_mmap__gtt(fd, buf->handle, buf->size,
> >> +                         PROT_READ | PROT_WRITE);
> >> +     igt_assert(ptr);
> >> +
> >> +     for (y = rect->y; y < rect->y + rect->h; y++) {
> >> +             int line_begin = y * buf->stride / sizeof(uint32_t);
> >> +             for (x = rect->x; x < rect->x + rect->w; x++)
> >> +                     ptr[line_begin + x] = color;
> >> +     }
> >> +
> >> +     igt_assert(munmap(ptr, buf->size) == 0);
> >> +}
> >> +
> >> +static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
> >> +                                  struct rect *rect, uint32_t color)
> >> +{
> >> +     uint32_t tmp[rect->w];
> >> +     int i, y, offset, bpp;
> >> +
> >> +     bpp = sizeof(uint32_t);
> >> +
> >> +     for (i = 0; i < rect->w; i++)
> >> +             tmp[i] = color;
> >> +
> >> +     for (y = rect->y; y < rect->y + rect->h; y++) {
> >> +             offset = (y * buf->stride) + (rect->x * bpp);
> >> +             gem_write(fd, buf->handle, offset, tmp, rect->w * bpp);
> >> +     }
> >> +}
> >> +
> >> +static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
> >> +                                struct rect *rect, uint32_t color,
> >> +                                uint32_t swizzle)
> >> +{
> >> +     int i;
> >> +     int tiled_pos, bpp, x, y;
> >> +     uint32_t tmp[1024];
> >> +     int tmp_used = 0, tmp_size = ARRAY_SIZE(tmp);
> >> +     bool flush_tmp = false;
> >> +     int tmp_start_pos = 0;
> >> +
> >> +     bpp = sizeof(uint32_t);
> >> +
> >> +     /* Instead of doing one pwrite per pixel, we try to group the maximum
> >> +      * amount of consecutive pixels we can in a single pwrite: that's why we
> >> +      * use the "tmp" variables. */
> >> +     for (i = 0; i < tmp_size; i++)
> >> +             tmp[i] = color;
> >> +
> >> +     for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += bpp) {
> >> +             tiled_pos_to_x_y_linear(tiled_pos, buf->stride, swizzle, &x, &y);
> >> +
> >> +             if (x >= rect->x && x < rect->x + rect->w &&
> >> +                 y >= rect->y && y < rect->y + rect->h) {
> >> +                     if (tmp_used == 0)
> >> +                             tmp_start_pos = tiled_pos;
> >> +                     tmp_used++;
> >> +             } else {
> >> +                     flush_tmp = true;
> >> +             }
> >> +
> >> +             if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0)) {
> >> +                     gem_write(fd, buf->handle, tmp_start_pos, tmp,
> >> +                               tmp_used * bpp);
> >> +                     flush_tmp = false;
> >> +                     tmp_used = 0;
> >> +             }
> >> +     }
> >> +}
> >> +
> >> +static void draw_rect_pwrite(int fd, struct buf_data *buf,
> >> +                          struct rect *rect, uint32_t color)
> >> +{
> >> +     uint32_t tiling, swizzle;
> >> +
> >> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> >> +
> >> +     if (tiling)
> >> +             draw_rect_pwrite_tiled(fd, buf, rect, color, swizzle);
> >> +     else
> >> +             draw_rect_pwrite_untiled(fd, buf, rect, color);
> >> +}
> >> +
> >> +static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
> >> +                       struct buf_data *buf, struct rect *rect,
> >> +                       uint32_t color)
> >> +{
> >> +     drm_intel_bo *dst;
> >> +     struct intel_batchbuffer *batch;
> >> +     int blt_cmd_len, blt_cmd_tiling;
> >> +     uint32_t devid = intel_get_drm_devid(fd);
> >> +     int gen = intel_gen(devid);
> >> +     uint32_t tiling, swizzle;
> >> +     int pitch;
> >> +
> >> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> >> +
> >> +     dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
> >> +     igt_assert(dst);
> >> +
> >> +     batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
> >> +     igt_assert(batch);
> >> +
> >> +     blt_cmd_len = (gen >= 8) ?  0x5 : 0x4;
> >> +     blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
> >> +     pitch = (tiling) ? buf->stride / 4 : buf->stride;
> >> +
> >> +     BEGIN_BATCH(6, 1);
> >
> > This breaks on gen8 because there the relocations are 2 dwords. You need
> > to use the magic macros for that.
> >
> 
> Please read the code again. I actually developed and tested everything
> on gen8 :)

Oh right I missed that OUT_RELOC uses qwords on gen8+ automatically. I
still think using the same logic as with all other blitter tests would be
better since blitter cmd copypaste fail has been the bane of igt.

> 
> >> +     OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
> >> +               XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
> >> +     OUT_BATCH((3 << 24) | (0xF0 << 16) | pitch);
> >> +     OUT_BATCH((rect->y << 16) | rect->x);
> >> +     OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
> >> +     if (tiling)

btw this isn't needed OUT_RELOC_FENCED works correctly for untiled
buffers. It's actually required on gen2/3 for untiled buffers if you reuse
buffers (which might be the case for a library function) since OUT_RELOC
does _not_ remove a stale fence if there is one.

> >> +             OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
> >> +     else
> >> +             OUT_RELOC(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
> >> +     OUT_BATCH(color);
> >> +     ADVANCE_BATCH();
> >> +
> >> +     intel_batchbuffer_flush(batch);
> >> +     gem_sync(fd, buf->handle);
> >> +     intel_batchbuffer_free(batch);
> >> +}
> >> +
> >> +static void draw_rect_render(int fd, struct cmd_data *cmd_data,
> >> +                          struct buf_data *buf, struct rect *rect,
> >> +                          uint32_t color)
> >> +{
> >> +     drm_intel_bo *src, *dst;
> >> +     uint32_t devid = intel_get_drm_devid(fd);
> >> +     igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
> >> +     struct igt_buf src_buf, dst_buf;
> >> +     struct intel_batchbuffer *batch;
> >> +     uint32_t tiling, swizzle;
> >> +     struct buf_data tmp;
> >> +
> >> +     igt_skip_on(!rendercopy);
> >> +
> >> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> >> +
> >> +     /* We create a temporary buffer and copy from it using rendercopy. */
> >> +     tmp.size = rect->w * rect->h * sizeof(uint32_t);
> >> +     tmp.handle = gem_create(fd, tmp.size);
> >> +     tmp.stride = rect->w * sizeof(uint32_t);
> >> +     draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
> >> +                        color);
> >> +
> >> +     src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
> >> +     igt_assert(src);
> >> +     dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
> >> +     igt_assert(dst);
> >> +
> >> +     src_buf.bo = src;
> >> +     src_buf.stride = tmp.stride;
> >> +     src_buf.tiling = I915_TILING_NONE;
> >> +     src_buf.size = tmp.size;
> >> +     dst_buf.bo = dst;
> >> +     dst_buf.stride = buf->stride;
> >> +     dst_buf.tiling = tiling;
> >> +     dst_buf.size = buf->size;
> >> +
> >> +     batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
> >> +     igt_assert(batch);
> >> +
> >> +     rendercopy(batch, cmd_data->context, &src_buf, 0, 0, rect->w, rect->h,
> >> +                &dst_buf, rect->x, rect->y);
> >> +
> >> +     gem_sync(fd, buf->handle);
> >> +     intel_batchbuffer_free(batch);
> >> +     gem_close(fd, tmp.handle);
> >> +}
> >> +
> >> +/**
> >> + * igt_draw_rect:
> >> + * @fd: the DRM file descriptor
> >> + * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
> >> + *          IGT_DRAW_RENDER
> >> + * @context: the context, can be NULL if you don't want to think about it
> >> + * @buf_handle: the handle of the buffer where you're going to draw to
> >> + * @buf_size: the size of the buffer
> >> + * @buf_stride: the stride of the buffer
> >> + * @method: method you're going to use to write to the buffer
> >> + * @rect_x: horizontal position on the buffer where your rectangle starts
> >> + * @rect_y: vertical position on the buffer where your rectangle starts
> >> + * @rect_w: width of the rectangle
> >> + * @rect_h: height of the rectangle
> >> + * @color: color of the rectangle
> >> + *
> >> + * This function draws a colored rectangle on the destination buffer, allowing
> >> + * you to specify the method used to draw the rectangle. We assume 32 bit pixels
> >> + * with 8 bits per color.
> >> + */
> >> +void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
> >> +                uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
> >> +                enum igt_draw_method method, int rect_x, int rect_y,
> >> +                int rect_w, int rect_h, uint32_t color)
> >> +{
> >> +     struct cmd_data cmd_data = {
> >> +             .bufmgr = bufmgr,
> >> +             .context = context,
> >> +     };
> >> +     struct buf_data buf = {
> >> +             .handle = buf_handle,
> >> +             .size = buf_size,
> >> +             .stride = buf_stride,
> >> +     };
> >> +     struct rect rect = {
> >> +             .x = rect_x,
> >> +             .y = rect_y,
> >> +             .w = rect_w,
> >> +             .h = rect_h,
> >> +     };
> >> +
> >> +     switch (method) {
> >> +     case IGT_DRAW_MMAP_CPU:
> >> +             draw_rect_mmap_cpu(fd, &buf, &rect, color);
> >> +             break;
> >> +     case IGT_DRAW_MMAP_GTT:
> >> +             draw_rect_mmap_gtt(fd, &buf, &rect, color);
> >> +             break;
> >> +     case IGT_DRAW_PWRITE:
> >> +             draw_rect_pwrite(fd, &buf, &rect, color);
> >> +             break;
> >> +     case IGT_DRAW_BLT:
> >> +             draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
> >> +             break;
> >> +     case IGT_DRAW_RENDER:
> >> +             draw_rect_render(fd, &cmd_data, &buf, &rect, color);
> >> +             break;
> >> +     default:
> >> +             igt_assert(false);
> >> +             break;
> >> +     }
> >> +}
> >> +
> >> +/**
> >> + * igt_draw_rect_fb:
> >> + *
> >> + * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
> >> + * of manually providing its details. See igt_draw_rect.
> >> + */
> >> +void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
> >> +                   drm_intel_context *context, struct igt_fb *fb,
> >> +                   enum igt_draw_method method, int rect_x, int rect_y,
> >> +                   int rect_w, int rect_h, uint32_t color)
> >> +{
> >> +     igt_draw_rect(fd, bufmgr, context, fb->gem_handle, fb->size, fb->stride,
> >> +                   method, rect_x, rect_y, rect_w, rect_h, color);
> >> +}
> >> +
> >> +/**
> >> + * igt_draw_fill_fb:
> >> + * @fd: the DRM file descriptor
> >> + * @fb: the FB that is going to be filled
> >> + * @color: the color you're going to paint it
> >> + *
> >> + * This function just paints an igt_fb using the provided color. It assumes 32
> >> + * bit pixels with 8 bit colors.
> >> + */
> >> +void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
> >> +{
> >> +     igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
> >> +                      0, 0, fb->width, fb->height, color);
> >> +}
> >> diff --git a/lib/igt_draw.h b/lib/igt_draw.h
> >> new file mode 100644
> >> index 0000000..399e17c
> >> --- /dev/null
> >> +++ b/lib/igt_draw.h
> >> @@ -0,0 +1,54 @@
> >> +/*
> >> + * Copyright © 2015 Intel Corporation
> >> + *
> >> + * Permission is hereby granted, free of charge, to any person obtaining a
> >> + * copy of this software and associated documentation files (the "Software"),
> >> + * to deal in the Software without restriction, including without limitation
> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> >> + * and/or sell copies of the Software, and to permit persons to whom the
> >> + * Software is furnished to do so, subject to the following conditions:
> >> + *
> >> + * The above copyright notice and this permission notice (including the next
> >> + * paragraph) shall be included in all copies or substantial portions of the
> >> + * Software.
> >> + *
> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> >> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> >> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> >> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> >> + * IN THE SOFTWARE.
> >> + *
> >> + */
> >> +
> >> +#ifndef __IGT_DRAW_H__
> >> +#define __IGT_DRAW_H__
> >> +
> >> +#include <intel_bufmgr.h>
> >> +#include "igt_fb.h"
> >> +
> >
> > gtkdoc for this enum would be nice too I think.
> 
> Ok.
> 
> 
> >
> >> +enum igt_draw_method {
> >> +     IGT_DRAW_MMAP_CPU,
> >> +     IGT_DRAW_MMAP_GTT,
> >> +     IGT_DRAW_PWRITE,
> >> +     IGT_DRAW_BLT,
> >> +     IGT_DRAW_RENDER,
> >> +     IGT_DRAW_METHOD_COUNT,
> >> +};
> >> +
> >> +const char *igt_draw_get_method_name(enum igt_draw_method method);
> >> +
> >> +void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
> >> +                uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
> >> +                enum igt_draw_method method, int rect_x, int rect_y,
> >> +                int rect_w, int rect_h, uint32_t color);
> >> +
> >> +void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
> >> +                   drm_intel_context *context, struct igt_fb *fb,
> >> +                   enum igt_draw_method method, int rect_x, int rect_y,
> >> +                   int rect_w, int rect_h, uint32_t color);
> >> +
> >> +void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color);
> >> +
> >> +#endif /* __IGT_DRAW_H__ */
> >> diff --git a/lib/tests/.gitignore b/lib/tests/.gitignore
> >> index a745a23..88f668a 100644
> >> --- a/lib/tests/.gitignore
> >> +++ b/lib/tests/.gitignore
> >> @@ -1,4 +1,5 @@
> >>  # Please keep sorted alphabetically
> >> +igt_draw
> >>  igt_fork_helper
> >>  igt_invalid_subtest_name
> >>  igt_list_only
> >> diff --git a/lib/tests/Makefile.sources b/lib/tests/Makefile.sources
> >> index ecd73ae..ff66d9d 100644
> >> --- a/lib/tests/Makefile.sources
> >> +++ b/lib/tests/Makefile.sources
> >> @@ -1,4 +1,5 @@
> >>  check_PROGRAMS = \
> >> +     igt_draw \
> >>       igt_no_exit \
> >>       igt_no_exit_list_only \
> >>       igt_fork_helper \
> >> diff --git a/lib/tests/igt_draw.c b/lib/tests/igt_draw.c
> >> new file mode 100644
> >> index 0000000..1630cc2
> >> --- /dev/null
> >> +++ b/lib/tests/igt_draw.c
> >> @@ -0,0 +1,247 @@
> >> +/*
> >> + * Copyright © 2015 Intel Corporation
> >> + *
> >> + * Permission is hereby granted, free of charge, to any person obtaining a
> >> + * copy of this software and associated documentation files (the "Software"),
> >> + * to deal in the Software without restriction, including without limitation
> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> >> + * and/or sell copies of the Software, and to permit persons to whom the
> >> + * Software is furnished to do so, subject to the following conditions:
> >> + *
> >> + * The above copyright notice and this permission notice (including the next
> >> + * paragraph) shall be included in all copies or substantial portions of the
> >> + * Software.
> >> + *
> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> >> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> >> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> >> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> >> + * IN THE SOFTWARE.
> >> + *
> >> + */
> >> +
> >> +/* This program tests whether the igt_draw library actually works. */
> >> +
> >> +#include "drmtest.h"
> >> +#include "igt_aux.h"
> >> +#include "igt_draw.h"
> >> +#include "igt_debugfs.h"
> >> +#include "igt_fb.h"
> >> +#include "igt_kms.h"
> >> +
> >> +#define MAX_CONNECTORS 32
> >> +
> >> +struct modeset_params {
> >> +     uint32_t crtc_id;
> >> +     uint32_t connector_id;
> >> +     drmModeModeInfoPtr mode;
> >> +};
> >> +
> >> +int drm_fd;
> >> +drmModeResPtr drm_res;
> >> +drmModeConnectorPtr drm_connectors[MAX_CONNECTORS];
> >> +drm_intel_bufmgr *bufmgr;
> >> +igt_pipe_crc_t *pipe_crc;
> >> +
> >> +bool has_method_base_crc = false;
> >> +igt_crc_t method_base_crc;
> >> +
> >> +struct modeset_params ms;
> >> +
> >> +static void find_modeset_params(void)
> >> +{
> >> +     int i;
> >> +     uint32_t connector_id = 0, crtc_id;
> >> +     drmModeModeInfoPtr mode = NULL;
> >> +
> >> +     for (i = 0; i < drm_res->count_connectors; i++) {
> >> +             drmModeConnectorPtr c = drm_connectors[i];
> >> +
> >> +             if (c->count_modes) {
> >> +                     connector_id = c->connector_id;
> >> +                     mode = &c->modes[0];
> >> +                     break;
> >> +             }
> >> +     }
> >> +     igt_require(connector_id);
> >> +
> >> +     crtc_id = drm_res->crtcs[0];
> >> +     igt_assert(crtc_id);
> >> +     igt_assert(mode);
> >> +
> >> +     ms.connector_id = connector_id;
> >> +     ms.crtc_id = crtc_id;
> >> +     ms.mode = mode;
> >> +
> >> +}
> >> +
> >> +static void get_method_crc(enum igt_draw_method method, uint64_t tiling,
> >> +                        igt_crc_t *crc)
> >> +{
> >> +     struct igt_fb fb;
> >> +     int rc;
> >> +
> >> +     igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
> >> +                   DRM_FORMAT_XRGB8888, tiling, &fb);
> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
> >> +                      0, 0, fb.width, fb.height, 0xFF);
> >> +
> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
> >> +                      fb.width / 4, fb.height / 4,
> >> +                      fb.width / 2, fb.height / 2, 0xFF00);
> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
> >> +                      fb.width / 8, fb.height / 8,
> >> +                      fb.width / 4, fb.height / 4, 0xFF0000);
> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
> >> +                      fb.width / 2, fb.height / 2,
> >> +                      fb.width / 3, fb.height / 3, 0xFF00FF);
> >> +
> >> +     rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
> >> +                         &ms.connector_id, 1, ms.mode);
> >> +     igt_assert(rc == 0);
> >> +
> >> +     igt_debug_wait_for_keypress("crc");
> >> +     igt_pipe_crc_collect_crc(pipe_crc, crc);
> >
> > Should we just move this igt_debug_wait_for_keypress into
> > igt_pipe_crc_collect_crc?
> 
> I think I prefer to leave these on the programs because you can then
> opt-out of some cases such as when you're getting the reference CRCs.
> It doesn't hurt to just add these to the problems, but it can be
> annoying if the wait is on the lib and you don't want it.

wait_for_keypress takes a key argument, so we could just use a "crc" key.
Test could then use a "check" or similar (we don't have a standard yet) -
generally you don't really want to run with --interactive-debug=all anyway
since that tends to stop awfully often already ;-) Also you can list
multiple keywords.

So annoying waits from libraries are already taken care of, no harm in
adding them.

> >> +
> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
> >> +     igt_remove_fb(drm_fd, &fb);
> >> +}
> >> +
> >> +static void draw_method_subtest(enum igt_draw_method method, uint64_t tiling)
> >> +{
> >> +     igt_crc_t crc;
> >> +
> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
> >> +
> >> +     find_modeset_params();
> >> +
> >> +     /* Use IGT_DRAW_MMAP_GTT on an untiled buffer as the parameter for
> >> +      * comparison. Cache the value so we don't recompute it for every single
> >> +      * subtest. */
> >> +     if (!has_method_base_crc) {
> >> +             get_method_crc(IGT_DRAW_MMAP_GTT, LOCAL_DRM_FORMAT_MOD_NONE,
> >> +                            &method_base_crc);
> >> +             has_method_base_crc = true;
> >> +     }
> >> +
> >> +     get_method_crc(method, tiling, &crc);
> >> +     igt_assert_crc_equal(&crc, &method_base_crc);
> >> +}
> >> +
> >> +static void get_fill_crc(uint64_t tiling, igt_crc_t *crc)
> >> +{
> >> +     struct igt_fb fb;
> >> +     int rc;
> >> +
> >> +     igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
> >> +                   DRM_FORMAT_XRGB8888, tiling, &fb);
> >> +
> >> +     igt_draw_fill_fb(drm_fd, &fb, 0xFF);
> >> +
> >> +     rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
> >> +                         &ms.connector_id, 1, ms.mode);
> >> +     igt_assert(rc == 0);
> >> +
> >> +     igt_debug_wait_for_keypress("crc");
> >> +     igt_pipe_crc_collect_crc(pipe_crc, crc);
> >> +
> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
> >> +     igt_remove_fb(drm_fd, &fb);
> >> +}
> >> +
> >> +static void fill_fb_subtest(void)
> >> +{
> >> +     int rc;
> >> +     struct igt_fb fb;
> >> +     igt_crc_t base_crc, crc;
> >> +
> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
> >> +
> >> +     find_modeset_params();
> >> +
> >> +     igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
> >> +                   DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb);
> >> +
> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, IGT_DRAW_MMAP_GTT,
> >> +                      0, 0, fb.width, fb.height, 0xFF);
> >> +
> >> +     rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
> >> +                         &ms.connector_id, 1, ms.mode);
> >> +     igt_assert(rc == 0);
> >> +
> >> +     igt_debug_wait_for_keypress("crc");
> >> +     igt_pipe_crc_collect_crc(pipe_crc, &base_crc);
> >> +
> >> +     get_fill_crc(LOCAL_DRM_FORMAT_MOD_NONE, &crc);
> >> +     igt_assert_crc_equal(&crc, &base_crc);
> >> +
> >> +     get_fill_crc(LOCAL_I915_FORMAT_MOD_X_TILED, &crc);
> >> +     igt_assert_crc_equal(&crc, &base_crc);
> >> +
> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
> >> +     igt_remove_fb(drm_fd, &fb);
> >> +}
> >> +
> >> +static void setup_environment(void)
> >> +{
> >> +     int i;
> >> +
> >> +     drm_fd = drm_open_any_master();
> >> +     igt_require(drm_fd >= 0);
> >> +
> >> +     drm_res = drmModeGetResources(drm_fd);
> >> +     igt_assert(drm_res->count_connectors <= MAX_CONNECTORS);
> >> +
> >> +     for (i = 0; i < drm_res->count_connectors; i++)
> >> +             drm_connectors[i] = drmModeGetConnector(drm_fd,
> >> +                                                     drm_res->connectors[i]);
> >> +
> >> +     kmstest_set_vt_graphics_mode();
> >> +
> >> +     bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
> >> +     igt_assert(bufmgr);
> >> +     drm_intel_bufmgr_gem_enable_reuse(bufmgr);
> >> +
> >> +     pipe_crc = igt_pipe_crc_new(0, INTEL_PIPE_CRC_SOURCE_AUTO);
> >> +}
> >> +
> >> +static void teardown_environment(void)
> >> +{
> >> +     int i;
> >> +
> >> +     igt_pipe_crc_free(pipe_crc);
> >> +
> >> +     drm_intel_bufmgr_destroy(bufmgr);
> >> +
> >> +     for (i = 0; i < drm_res->count_connectors; i++)
> >> +             drmModeFreeConnector(drm_connectors[i]);
> >> +
> >> +     drmModeFreeResources(drm_res);
> >> +     close(drm_fd);
> >> +}
> >> +
> >> +igt_main
> >> +{
> >> +     enum igt_draw_method method;
> >> +
> >> +     igt_fixture
> >> +             setup_environment();
> >> +
> >> +     for (method = 0; method < IGT_DRAW_METHOD_COUNT; method++) {
> >> +             igt_subtest_f("draw-method-%s-untiled",
> >> +                           igt_draw_get_method_name(method))
> >> +                     draw_method_subtest(method, LOCAL_DRM_FORMAT_MOD_NONE);
> >> +             igt_subtest_f("draw-method-%s-tiled",
> >> +                           igt_draw_get_method_name(method))
> >> +                     draw_method_subtest(method,
> >> +                                         LOCAL_I915_FORMAT_MOD_X_TILED);
> >> +     }
> >> +
> >> +     igt_subtest("fill-fb")
> >> +             fill_fb_subtest();
> >> +
> >> +     igt_fixture
> >> +             teardown_environment();
> >> +}
> >> --
> >> 2.1.4
> >>
> >> _______________________________________________
> >> Intel-gfx mailing list
> >> Intel-gfx@lists.freedesktop.org
> >> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch
> 
> 
> 
> -- 
> Paulo Zanoni

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-03-31 13:07       ` Daniel Vetter
@ 2015-03-31 14:03         ` Paulo Zanoni
  2015-03-31 21:52           ` Paulo Zanoni
  0 siblings, 1 reply; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-31 14:03 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, Paulo Zanoni

2015-03-31 10:07 GMT-03:00 Daniel Vetter <daniel@ffwll.ch>:
> On Mon, Mar 30, 2015 at 04:45:49PM -0300, Paulo Zanoni wrote:
>> 2015-03-26 7:19 GMT-03:00 Daniel Vetter <daniel@ffwll.ch>:
>> > On Wed, Mar 25, 2015 at 06:50:39PM -0300, Paulo Zanoni wrote:
>> >> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
>> >>
>> >> For all those IGT tests that need an easy way to draw rectangles on
>> >> buffers using different methods. Current planned users: FBC and PSR
>> >> CRC tests.
>> >>
>> >> There is also a lib/tests/igt_draw program to check if the library is
>> >> sane.
>> >
>> > We need to move that to tests/igt_draw. The testcase in lib/tests/* get
>> > run with make check, which must be possible as non-root on a non-intel
>> > (build) machine. If you need an gpu to run your test it must be in tests/*
>> > as a normal igt kernel test.
>> >
>> > Wrt the library itself I'm unsure about the explicit tiling/swizzling.
>> > Your current code only works on gen5-8 and maintaining a full-blown
>> > swizzle/tiling library is real work, and means some of the tests can't be
>> > converted to this.
>>
>> This would just be a problem for the tests that use it, and no test is
>> using it yet. This is just for the cases where you want to use the CPU
>> to write into tiled buffers.
>>
>> If we start using this in a test, then we need to properly test all
>> the affected platforms. I have some local FBC tests that use it -
>> which I was going to submit after getting feedback on this lib -, and
>> I don't think we'll end needing to run these tests on the older
>> platforms.
>>
>>
>> > We do have all the tiling modes encoded in the tiling
>> > tests though, so if you have a lot of time it might be useful to extract
>> > tiling helpers into the igt library which work on all generations.
>>
>> Can you please be more precise here? Where exactly should I look?
>
> gem_tiled_pread has the full-blown tiling/swizzle logic for all platforms.
> This is the one test we have which should work everywhere.
>
> My concern is that by implementing a library which doesn't support
> everywhere we havea  bit a split in the testbase which might surprise
> people. Imo a library function should work everywhere. If you look at the
> code in there compared to yours there's just 2 things missing:
> - Variable tile size/height.
> - Some of the more crazy swizzle modes.
>
> Also if we have a library which works everywhere we could extend it with
> the new fancy gen9+ tiling modes.

I'll take a look at gem_tiled_pread and try to implement what is
missing. I agree that supporting everything is the ideal, but I also
think that we can grow this support as needed instead of all at once.

>
>> > I think we should at least have a fallback mode which allows us to fill an
>> > entire buffer completely (i.e. not just the hxw area) and treat it as
>> > untiled.
>>
>> That is not the goal of the library. Still, if we ever need this
>> function, it would be easy to add.
>
> That was just meant as a fallback for buffers where you don't support the
> exact tiling/swizzling mode.
>>
>> >
>> > More comments below.
>>
>> More below too :)
>>
>> > -Daniel
>> >
>> >>
>> >> Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
>> >> ---
>> >>  lib/Makefile.sources       |   2 +
>> >>  lib/igt_draw.c             | 467 +++++++++++++++++++++++++++++++++++++++++++++
>> >>  lib/igt_draw.h             |  54 ++++++
>> >>  lib/tests/.gitignore       |   1 +
>> >>  lib/tests/Makefile.sources |   1 +
>> >>  lib/tests/igt_draw.c       | 247 ++++++++++++++++++++++++
>> >>  6 files changed, 772 insertions(+)
>> >>  create mode 100644 lib/igt_draw.c
>> >>  create mode 100644 lib/igt_draw.h
>> >>  create mode 100644 lib/tests/igt_draw.c
>> >>
>> >> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
>> >> index 3d93629..85dc321 100644
>> >> --- a/lib/Makefile.sources
>> >> +++ b/lib/Makefile.sources
>> >> @@ -52,6 +52,8 @@ libintel_tools_la_SOURCES =         \
>> >>       igt_fb.h                \
>> >>       igt_core.c              \
>> >>       igt_core.h              \
>> >> +     igt_draw.c              \
>> >> +     igt_draw.h              \
>> >>       $(NULL)
>> >>
>> >>  .PHONY: version.h.tmp
>> >> diff --git a/lib/igt_draw.c b/lib/igt_draw.c
>> >> new file mode 100644
>> >> index 0000000..4eb7507
>> >> --- /dev/null
>> >> +++ b/lib/igt_draw.c
>> >> @@ -0,0 +1,467 @@
>> >> +/*
>> >> + * Copyright © 2015 Intel Corporation
>> >> + *
>> >> + * Permission is hereby granted, free of charge, to any person obtaining a
>> >> + * copy of this software and associated documentation files (the "Software"),
>> >> + * to deal in the Software without restriction, including without limitation
>> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> >> + * and/or sell copies of the Software, and to permit persons to whom the
>> >> + * Software is furnished to do so, subject to the following conditions:
>> >> + *
>> >> + * The above copyright notice and this permission notice (including the next
>> >> + * paragraph) shall be included in all copies or substantial portions of the
>> >> + * Software.
>> >> + *
>> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> >> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> >> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> >> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> >> + * IN THE SOFTWARE.
>> >> + *
>> >> + */
>> >> +
>> >> +#include <sys/mman.h>
>> >> +
>> >> +#include "igt_draw.h"
>> >> +
>> >> +#include "drmtest.h"
>> >> +#include "intel_chipset.h"
>> >> +#include "igt_core.h"
>> >> +#include "igt_fb.h"
>> >> +#include "ioctl_wrappers.h"
>> >> +
>> >> +/**
>> >> + * SECTION:igt_draw
>> >> + * @short_description: drawing helpers for tests
>> >> + * @title: i-g-t draw
>> >> + * @include: igt_draw.h
>> >> + *
>> >> + * This library contains some functions for drawing rectangles on buffers using
>> >> + * the many different drawing methods we have. It also contains some wrappers
>> >> + * that make the process easier if you have the abstract objects in hand.
>> >> + *
>> >> + * All functions assume the buffers are in the XRGB 8:8:8 format.
>> >> + *
>> >> + */
>> >> +
>> >> +/* Some internal data structures to avoid having to pass tons of parameters
>> >> + * around everything. */
>> >> +struct cmd_data {
>> >> +     drm_intel_bufmgr *bufmgr;
>> >> +     drm_intel_context *context;
>> >> +};
>> >> +
>> >> +struct buf_data {
>> >> +     uint32_t handle;
>> >> +     uint32_t size;
>> >> +     uint32_t stride;
>> >> +};
>> >> +
>> >> +struct rect {
>> >> +     int x;
>> >> +     int y;
>> >> +     int w;
>> >> +     int h;
>> >> +};
>> >> +
>> >> +const char *igt_draw_get_method_name(enum igt_draw_method method)
>> >> +{
>> >> +     switch (method) {
>> >> +     case IGT_DRAW_MMAP_CPU:
>> >> +             return "mmap-cpu";
>> >> +     case IGT_DRAW_MMAP_GTT:
>> >> +             return "mmap-gtt";
>> >> +     case IGT_DRAW_PWRITE:
>> >> +             return "pwrite";
>> >> +     case IGT_DRAW_BLT:
>> >> +             return "blt";
>> >> +     case IGT_DRAW_RENDER:
>> >> +             return "render";
>> >> +     default:
>> >> +             igt_assert(false);
>> >> +     }
>> >> +}
>> >> +
>> >> +static int swizzle_addr(int addr, int swizzle)
>> >> +{
>> >> +     int bit6;
>> >> +
>> >> +     if (swizzle == I915_BIT_6_SWIZZLE_9_10) {
>> >> +             bit6 = ((addr >> 6) & 1) ^ ((addr >> 9) & 1) ^
>> >> +                    ((addr >> 10) & 1);
>> >> +             addr &= ~(1 << 6);
>> >> +             addr |= (bit6 << 6);
>> >> +     }
>> >> +
>> >> +     return addr;
>> >> +}
>> >> +
>> >> +/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
>> >> + * if you need to. */
>> >> +static int linear_x_y_to_tiled_pos(int x, int y, uint32_t stride, int swizzle)
>> >> +{
>> >> +     int x_tile_size, y_tile_size;
>> >> +     int x_tile_n, y_tile_n, x_tile_off, y_tile_off;
>> >> +     int line_size, tile_size;
>> >> +     int tile_n, tile_off;
>> >> +     int tiled_pos, tiles_per_line;
>> >> +     int bpp;
>> >> +
>> >> +     line_size = stride;
>> >> +     x_tile_size = 512;
>> >> +     y_tile_size = 8;
>> >> +     tile_size = x_tile_size * y_tile_size;
>> >> +     tiles_per_line = line_size / x_tile_size;
>> >> +     bpp = sizeof(uint32_t);
>> >> +
>> >> +     y_tile_n = y / y_tile_size;
>> >> +     y_tile_off = y % y_tile_size;
>> >> +
>> >> +     x_tile_n = (x * bpp) / x_tile_size;
>> >> +     x_tile_off = (x * bpp) % x_tile_size;
>> >> +
>> >> +     tile_n = y_tile_n * tiles_per_line + x_tile_n;
>> >> +     tile_off = y_tile_off * x_tile_size + x_tile_off;
>> >> +     tiled_pos = tile_n * tile_size + tile_off;
>> >> +
>> >> +     tiled_pos = swizzle_addr(tiled_pos, swizzle);
>> >> +
>> >> +     return tiled_pos / bpp;
>> >> +}
>> >> +
>> >> +/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
>> >> + * if you need to. */
>> >> +static void tiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
>> >> +                                 int swizzle, int *x, int *y)
>> >> +{
>> >> +     int tile_n, tile_off, tiles_per_line, line_size;
>> >> +     int x_tile_off, y_tile_off;
>> >> +     int x_tile_n, y_tile_n;
>> >> +     int x_tile_size, y_tile_size, tile_size;
>> >> +     int bpp;
>> >> +
>> >> +     tiled_pos = swizzle_addr(tiled_pos, swizzle);
>> >> +
>> >> +     line_size = stride;
>> >> +     x_tile_size = 512;
>> >> +     y_tile_size = 8;
>> >> +     tile_size = x_tile_size * y_tile_size;
>> >> +     tiles_per_line = line_size / x_tile_size;
>> >> +     bpp = sizeof(uint32_t);
>> >> +
>> >> +     tile_n = tiled_pos / tile_size;
>> >> +     tile_off = tiled_pos % tile_size;
>> >> +
>> >> +     y_tile_off = tile_off / x_tile_size;
>> >> +     x_tile_off = tile_off % x_tile_size;
>> >> +
>> >> +     x_tile_n = tile_n % tiles_per_line;
>> >> +     y_tile_n = tile_n / tiles_per_line;
>> >> +
>> >> +     *x = (x_tile_n * x_tile_size + x_tile_off) / bpp;
>> >> +     *y = y_tile_n * y_tile_size + y_tile_off;
>> >> +}
>> >> +
>> >> +static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
>> >> +                            uint32_t color)
>> >> +{
>> >> +     uint32_t *ptr;
>> >> +     int x, y, pos;
>> >> +     uint32_t tiling, swizzle;
>> >> +
>> >> +     gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
>> >> +                    I915_GEM_DOMAIN_CPU);
>> >> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
>> >> +
>> >> +     ptr = gem_mmap__cpu(fd, buf->handle, 0, buf->size, 0);
>> >> +     igt_assert(ptr);
>> >> +
>> >> +     for (y = rect->y; y < rect->y + rect->h; y++) {
>> >> +             for (x = rect->x; x < rect->x + rect->w; x++) {
>> >> +                     if (tiling)
>> >> +                             pos = linear_x_y_to_tiled_pos(x, y, buf->stride,
>> >> +                                                           swizzle);
>> >> +                     else
>> >> +                             pos = (y * buf->stride / sizeof(uint32_t)) + x;
>> >> +                     ptr[pos] = color;
>> >> +             }
>> >> +     }
>> >> +
>> >> +     gem_sw_finish(fd, buf->handle);
>> >> +
>> >> +     igt_assert(munmap(ptr, buf->size) == 0);
>> >> +}
>> >> +
>> >> +static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
>> >> +                            uint32_t color)
>> >> +{
>> >> +     uint32_t *ptr;
>> >> +     int x, y;
>> >> +
>> >> +     ptr = gem_mmap__gtt(fd, buf->handle, buf->size,
>> >> +                         PROT_READ | PROT_WRITE);
>> >> +     igt_assert(ptr);
>> >> +
>> >> +     for (y = rect->y; y < rect->y + rect->h; y++) {
>> >> +             int line_begin = y * buf->stride / sizeof(uint32_t);
>> >> +             for (x = rect->x; x < rect->x + rect->w; x++)
>> >> +                     ptr[line_begin + x] = color;
>> >> +     }
>> >> +
>> >> +     igt_assert(munmap(ptr, buf->size) == 0);
>> >> +}
>> >> +
>> >> +static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
>> >> +                                  struct rect *rect, uint32_t color)
>> >> +{
>> >> +     uint32_t tmp[rect->w];
>> >> +     int i, y, offset, bpp;
>> >> +
>> >> +     bpp = sizeof(uint32_t);
>> >> +
>> >> +     for (i = 0; i < rect->w; i++)
>> >> +             tmp[i] = color;
>> >> +
>> >> +     for (y = rect->y; y < rect->y + rect->h; y++) {
>> >> +             offset = (y * buf->stride) + (rect->x * bpp);
>> >> +             gem_write(fd, buf->handle, offset, tmp, rect->w * bpp);
>> >> +     }
>> >> +}
>> >> +
>> >> +static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
>> >> +                                struct rect *rect, uint32_t color,
>> >> +                                uint32_t swizzle)
>> >> +{
>> >> +     int i;
>> >> +     int tiled_pos, bpp, x, y;
>> >> +     uint32_t tmp[1024];
>> >> +     int tmp_used = 0, tmp_size = ARRAY_SIZE(tmp);
>> >> +     bool flush_tmp = false;
>> >> +     int tmp_start_pos = 0;
>> >> +
>> >> +     bpp = sizeof(uint32_t);
>> >> +
>> >> +     /* Instead of doing one pwrite per pixel, we try to group the maximum
>> >> +      * amount of consecutive pixels we can in a single pwrite: that's why we
>> >> +      * use the "tmp" variables. */
>> >> +     for (i = 0; i < tmp_size; i++)
>> >> +             tmp[i] = color;
>> >> +
>> >> +     for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += bpp) {
>> >> +             tiled_pos_to_x_y_linear(tiled_pos, buf->stride, swizzle, &x, &y);
>> >> +
>> >> +             if (x >= rect->x && x < rect->x + rect->w &&
>> >> +                 y >= rect->y && y < rect->y + rect->h) {
>> >> +                     if (tmp_used == 0)
>> >> +                             tmp_start_pos = tiled_pos;
>> >> +                     tmp_used++;
>> >> +             } else {
>> >> +                     flush_tmp = true;
>> >> +             }
>> >> +
>> >> +             if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0)) {
>> >> +                     gem_write(fd, buf->handle, tmp_start_pos, tmp,
>> >> +                               tmp_used * bpp);
>> >> +                     flush_tmp = false;
>> >> +                     tmp_used = 0;
>> >> +             }
>> >> +     }
>> >> +}
>> >> +
>> >> +static void draw_rect_pwrite(int fd, struct buf_data *buf,
>> >> +                          struct rect *rect, uint32_t color)
>> >> +{
>> >> +     uint32_t tiling, swizzle;
>> >> +
>> >> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
>> >> +
>> >> +     if (tiling)
>> >> +             draw_rect_pwrite_tiled(fd, buf, rect, color, swizzle);
>> >> +     else
>> >> +             draw_rect_pwrite_untiled(fd, buf, rect, color);
>> >> +}
>> >> +
>> >> +static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
>> >> +                       struct buf_data *buf, struct rect *rect,
>> >> +                       uint32_t color)
>> >> +{
>> >> +     drm_intel_bo *dst;
>> >> +     struct intel_batchbuffer *batch;
>> >> +     int blt_cmd_len, blt_cmd_tiling;
>> >> +     uint32_t devid = intel_get_drm_devid(fd);
>> >> +     int gen = intel_gen(devid);
>> >> +     uint32_t tiling, swizzle;
>> >> +     int pitch;
>> >> +
>> >> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
>> >> +
>> >> +     dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
>> >> +     igt_assert(dst);
>> >> +
>> >> +     batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
>> >> +     igt_assert(batch);
>> >> +
>> >> +     blt_cmd_len = (gen >= 8) ?  0x5 : 0x4;
>> >> +     blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
>> >> +     pitch = (tiling) ? buf->stride / 4 : buf->stride;
>> >> +
>> >> +     BEGIN_BATCH(6, 1);
>> >
>> > This breaks on gen8 because there the relocations are 2 dwords. You need
>> > to use the magic macros for that.
>> >
>>
>> Please read the code again. I actually developed and tested everything
>> on gen8 :)
>
> Oh right I missed that OUT_RELOC uses qwords on gen8+ automatically. I
> still think using the same logic as with all other blitter tests would be
> better since blitter cmd copypaste fail has been the bane of igt.

Well, this is one of the main goals of the library: use it instead of
adding yet another implementation of the drawing commands...

>
>>
>> >> +     OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
>> >> +               XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
>> >> +     OUT_BATCH((3 << 24) | (0xF0 << 16) | pitch);
>> >> +     OUT_BATCH((rect->y << 16) | rect->x);
>> >> +     OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
>> >> +     if (tiling)
>
> btw this isn't needed OUT_RELOC_FENCED works correctly for untiled
> buffers. It's actually required on gen2/3 for untiled buffers if you reuse
> buffers (which might be the case for a library function) since OUT_RELOC
> does _not_ remove a stale fence if there is one.
>
>> >> +             OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
>> >> +     else
>> >> +             OUT_RELOC(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
>> >> +     OUT_BATCH(color);
>> >> +     ADVANCE_BATCH();
>> >> +
>> >> +     intel_batchbuffer_flush(batch);
>> >> +     gem_sync(fd, buf->handle);
>> >> +     intel_batchbuffer_free(batch);
>> >> +}
>> >> +
>> >> +static void draw_rect_render(int fd, struct cmd_data *cmd_data,
>> >> +                          struct buf_data *buf, struct rect *rect,
>> >> +                          uint32_t color)
>> >> +{
>> >> +     drm_intel_bo *src, *dst;
>> >> +     uint32_t devid = intel_get_drm_devid(fd);
>> >> +     igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
>> >> +     struct igt_buf src_buf, dst_buf;
>> >> +     struct intel_batchbuffer *batch;
>> >> +     uint32_t tiling, swizzle;
>> >> +     struct buf_data tmp;
>> >> +
>> >> +     igt_skip_on(!rendercopy);
>> >> +
>> >> +     gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
>> >> +
>> >> +     /* We create a temporary buffer and copy from it using rendercopy. */
>> >> +     tmp.size = rect->w * rect->h * sizeof(uint32_t);
>> >> +     tmp.handle = gem_create(fd, tmp.size);
>> >> +     tmp.stride = rect->w * sizeof(uint32_t);
>> >> +     draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
>> >> +                        color);
>> >> +
>> >> +     src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
>> >> +     igt_assert(src);
>> >> +     dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
>> >> +     igt_assert(dst);
>> >> +
>> >> +     src_buf.bo = src;
>> >> +     src_buf.stride = tmp.stride;
>> >> +     src_buf.tiling = I915_TILING_NONE;
>> >> +     src_buf.size = tmp.size;
>> >> +     dst_buf.bo = dst;
>> >> +     dst_buf.stride = buf->stride;
>> >> +     dst_buf.tiling = tiling;
>> >> +     dst_buf.size = buf->size;
>> >> +
>> >> +     batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
>> >> +     igt_assert(batch);
>> >> +
>> >> +     rendercopy(batch, cmd_data->context, &src_buf, 0, 0, rect->w, rect->h,
>> >> +                &dst_buf, rect->x, rect->y);
>> >> +
>> >> +     gem_sync(fd, buf->handle);
>> >> +     intel_batchbuffer_free(batch);
>> >> +     gem_close(fd, tmp.handle);
>> >> +}
>> >> +
>> >> +/**
>> >> + * igt_draw_rect:
>> >> + * @fd: the DRM file descriptor
>> >> + * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
>> >> + *          IGT_DRAW_RENDER
>> >> + * @context: the context, can be NULL if you don't want to think about it
>> >> + * @buf_handle: the handle of the buffer where you're going to draw to
>> >> + * @buf_size: the size of the buffer
>> >> + * @buf_stride: the stride of the buffer
>> >> + * @method: method you're going to use to write to the buffer
>> >> + * @rect_x: horizontal position on the buffer where your rectangle starts
>> >> + * @rect_y: vertical position on the buffer where your rectangle starts
>> >> + * @rect_w: width of the rectangle
>> >> + * @rect_h: height of the rectangle
>> >> + * @color: color of the rectangle
>> >> + *
>> >> + * This function draws a colored rectangle on the destination buffer, allowing
>> >> + * you to specify the method used to draw the rectangle. We assume 32 bit pixels
>> >> + * with 8 bits per color.
>> >> + */
>> >> +void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
>> >> +                uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
>> >> +                enum igt_draw_method method, int rect_x, int rect_y,
>> >> +                int rect_w, int rect_h, uint32_t color)
>> >> +{
>> >> +     struct cmd_data cmd_data = {
>> >> +             .bufmgr = bufmgr,
>> >> +             .context = context,
>> >> +     };
>> >> +     struct buf_data buf = {
>> >> +             .handle = buf_handle,
>> >> +             .size = buf_size,
>> >> +             .stride = buf_stride,
>> >> +     };
>> >> +     struct rect rect = {
>> >> +             .x = rect_x,
>> >> +             .y = rect_y,
>> >> +             .w = rect_w,
>> >> +             .h = rect_h,
>> >> +     };
>> >> +
>> >> +     switch (method) {
>> >> +     case IGT_DRAW_MMAP_CPU:
>> >> +             draw_rect_mmap_cpu(fd, &buf, &rect, color);
>> >> +             break;
>> >> +     case IGT_DRAW_MMAP_GTT:
>> >> +             draw_rect_mmap_gtt(fd, &buf, &rect, color);
>> >> +             break;
>> >> +     case IGT_DRAW_PWRITE:
>> >> +             draw_rect_pwrite(fd, &buf, &rect, color);
>> >> +             break;
>> >> +     case IGT_DRAW_BLT:
>> >> +             draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
>> >> +             break;
>> >> +     case IGT_DRAW_RENDER:
>> >> +             draw_rect_render(fd, &cmd_data, &buf, &rect, color);
>> >> +             break;
>> >> +     default:
>> >> +             igt_assert(false);
>> >> +             break;
>> >> +     }
>> >> +}
>> >> +
>> >> +/**
>> >> + * igt_draw_rect_fb:
>> >> + *
>> >> + * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
>> >> + * of manually providing its details. See igt_draw_rect.
>> >> + */
>> >> +void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
>> >> +                   drm_intel_context *context, struct igt_fb *fb,
>> >> +                   enum igt_draw_method method, int rect_x, int rect_y,
>> >> +                   int rect_w, int rect_h, uint32_t color)
>> >> +{
>> >> +     igt_draw_rect(fd, bufmgr, context, fb->gem_handle, fb->size, fb->stride,
>> >> +                   method, rect_x, rect_y, rect_w, rect_h, color);
>> >> +}
>> >> +
>> >> +/**
>> >> + * igt_draw_fill_fb:
>> >> + * @fd: the DRM file descriptor
>> >> + * @fb: the FB that is going to be filled
>> >> + * @color: the color you're going to paint it
>> >> + *
>> >> + * This function just paints an igt_fb using the provided color. It assumes 32
>> >> + * bit pixels with 8 bit colors.
>> >> + */
>> >> +void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
>> >> +{
>> >> +     igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
>> >> +                      0, 0, fb->width, fb->height, color);
>> >> +}
>> >> diff --git a/lib/igt_draw.h b/lib/igt_draw.h
>> >> new file mode 100644
>> >> index 0000000..399e17c
>> >> --- /dev/null
>> >> +++ b/lib/igt_draw.h
>> >> @@ -0,0 +1,54 @@
>> >> +/*
>> >> + * Copyright © 2015 Intel Corporation
>> >> + *
>> >> + * Permission is hereby granted, free of charge, to any person obtaining a
>> >> + * copy of this software and associated documentation files (the "Software"),
>> >> + * to deal in the Software without restriction, including without limitation
>> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> >> + * and/or sell copies of the Software, and to permit persons to whom the
>> >> + * Software is furnished to do so, subject to the following conditions:
>> >> + *
>> >> + * The above copyright notice and this permission notice (including the next
>> >> + * paragraph) shall be included in all copies or substantial portions of the
>> >> + * Software.
>> >> + *
>> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> >> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> >> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> >> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> >> + * IN THE SOFTWARE.
>> >> + *
>> >> + */
>> >> +
>> >> +#ifndef __IGT_DRAW_H__
>> >> +#define __IGT_DRAW_H__
>> >> +
>> >> +#include <intel_bufmgr.h>
>> >> +#include "igt_fb.h"
>> >> +
>> >
>> > gtkdoc for this enum would be nice too I think.
>>
>> Ok.
>>
>>
>> >
>> >> +enum igt_draw_method {
>> >> +     IGT_DRAW_MMAP_CPU,
>> >> +     IGT_DRAW_MMAP_GTT,
>> >> +     IGT_DRAW_PWRITE,
>> >> +     IGT_DRAW_BLT,
>> >> +     IGT_DRAW_RENDER,
>> >> +     IGT_DRAW_METHOD_COUNT,
>> >> +};
>> >> +
>> >> +const char *igt_draw_get_method_name(enum igt_draw_method method);
>> >> +
>> >> +void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
>> >> +                uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
>> >> +                enum igt_draw_method method, int rect_x, int rect_y,
>> >> +                int rect_w, int rect_h, uint32_t color);
>> >> +
>> >> +void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
>> >> +                   drm_intel_context *context, struct igt_fb *fb,
>> >> +                   enum igt_draw_method method, int rect_x, int rect_y,
>> >> +                   int rect_w, int rect_h, uint32_t color);
>> >> +
>> >> +void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color);
>> >> +
>> >> +#endif /* __IGT_DRAW_H__ */
>> >> diff --git a/lib/tests/.gitignore b/lib/tests/.gitignore
>> >> index a745a23..88f668a 100644
>> >> --- a/lib/tests/.gitignore
>> >> +++ b/lib/tests/.gitignore
>> >> @@ -1,4 +1,5 @@
>> >>  # Please keep sorted alphabetically
>> >> +igt_draw
>> >>  igt_fork_helper
>> >>  igt_invalid_subtest_name
>> >>  igt_list_only
>> >> diff --git a/lib/tests/Makefile.sources b/lib/tests/Makefile.sources
>> >> index ecd73ae..ff66d9d 100644
>> >> --- a/lib/tests/Makefile.sources
>> >> +++ b/lib/tests/Makefile.sources
>> >> @@ -1,4 +1,5 @@
>> >>  check_PROGRAMS = \
>> >> +     igt_draw \
>> >>       igt_no_exit \
>> >>       igt_no_exit_list_only \
>> >>       igt_fork_helper \
>> >> diff --git a/lib/tests/igt_draw.c b/lib/tests/igt_draw.c
>> >> new file mode 100644
>> >> index 0000000..1630cc2
>> >> --- /dev/null
>> >> +++ b/lib/tests/igt_draw.c
>> >> @@ -0,0 +1,247 @@
>> >> +/*
>> >> + * Copyright © 2015 Intel Corporation
>> >> + *
>> >> + * Permission is hereby granted, free of charge, to any person obtaining a
>> >> + * copy of this software and associated documentation files (the "Software"),
>> >> + * to deal in the Software without restriction, including without limitation
>> >> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> >> + * and/or sell copies of the Software, and to permit persons to whom the
>> >> + * Software is furnished to do so, subject to the following conditions:
>> >> + *
>> >> + * The above copyright notice and this permission notice (including the next
>> >> + * paragraph) shall be included in all copies or substantial portions of the
>> >> + * Software.
>> >> + *
>> >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> >> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> >> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> >> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> >> + * IN THE SOFTWARE.
>> >> + *
>> >> + */
>> >> +
>> >> +/* This program tests whether the igt_draw library actually works. */
>> >> +
>> >> +#include "drmtest.h"
>> >> +#include "igt_aux.h"
>> >> +#include "igt_draw.h"
>> >> +#include "igt_debugfs.h"
>> >> +#include "igt_fb.h"
>> >> +#include "igt_kms.h"
>> >> +
>> >> +#define MAX_CONNECTORS 32
>> >> +
>> >> +struct modeset_params {
>> >> +     uint32_t crtc_id;
>> >> +     uint32_t connector_id;
>> >> +     drmModeModeInfoPtr mode;
>> >> +};
>> >> +
>> >> +int drm_fd;
>> >> +drmModeResPtr drm_res;
>> >> +drmModeConnectorPtr drm_connectors[MAX_CONNECTORS];
>> >> +drm_intel_bufmgr *bufmgr;
>> >> +igt_pipe_crc_t *pipe_crc;
>> >> +
>> >> +bool has_method_base_crc = false;
>> >> +igt_crc_t method_base_crc;
>> >> +
>> >> +struct modeset_params ms;
>> >> +
>> >> +static void find_modeset_params(void)
>> >> +{
>> >> +     int i;
>> >> +     uint32_t connector_id = 0, crtc_id;
>> >> +     drmModeModeInfoPtr mode = NULL;
>> >> +
>> >> +     for (i = 0; i < drm_res->count_connectors; i++) {
>> >> +             drmModeConnectorPtr c = drm_connectors[i];
>> >> +
>> >> +             if (c->count_modes) {
>> >> +                     connector_id = c->connector_id;
>> >> +                     mode = &c->modes[0];
>> >> +                     break;
>> >> +             }
>> >> +     }
>> >> +     igt_require(connector_id);
>> >> +
>> >> +     crtc_id = drm_res->crtcs[0];
>> >> +     igt_assert(crtc_id);
>> >> +     igt_assert(mode);
>> >> +
>> >> +     ms.connector_id = connector_id;
>> >> +     ms.crtc_id = crtc_id;
>> >> +     ms.mode = mode;
>> >> +
>> >> +}
>> >> +
>> >> +static void get_method_crc(enum igt_draw_method method, uint64_t tiling,
>> >> +                        igt_crc_t *crc)
>> >> +{
>> >> +     struct igt_fb fb;
>> >> +     int rc;
>> >> +
>> >> +     igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
>> >> +                   DRM_FORMAT_XRGB8888, tiling, &fb);
>> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
>> >> +                      0, 0, fb.width, fb.height, 0xFF);
>> >> +
>> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
>> >> +                      fb.width / 4, fb.height / 4,
>> >> +                      fb.width / 2, fb.height / 2, 0xFF00);
>> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
>> >> +                      fb.width / 8, fb.height / 8,
>> >> +                      fb.width / 4, fb.height / 4, 0xFF0000);
>> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
>> >> +                      fb.width / 2, fb.height / 2,
>> >> +                      fb.width / 3, fb.height / 3, 0xFF00FF);
>> >> +
>> >> +     rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
>> >> +                         &ms.connector_id, 1, ms.mode);
>> >> +     igt_assert(rc == 0);
>> >> +
>> >> +     igt_debug_wait_for_keypress("crc");
>> >> +     igt_pipe_crc_collect_crc(pipe_crc, crc);
>> >
>> > Should we just move this igt_debug_wait_for_keypress into
>> > igt_pipe_crc_collect_crc?
>>
>> I think I prefer to leave these on the programs because you can then
>> opt-out of some cases such as when you're getting the reference CRCs.
>> It doesn't hurt to just add these to the problems, but it can be
>> annoying if the wait is on the lib and you don't want it.
>
> wait_for_keypress takes a key argument, so we could just use a "crc" key.
> Test could then use a "check" or similar (we don't have a standard yet) -
> generally you don't really want to run with --interactive-debug=all anyway
> since that tends to stop awfully often already ;-) Also you can list
> multiple keywords.
>
> So annoying waits from libraries are already taken care of, no harm in
> adding them.
>

Ok, I agree with you here now.


>> >> +
>> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> >> +     igt_remove_fb(drm_fd, &fb);
>> >> +}
>> >> +
>> >> +static void draw_method_subtest(enum igt_draw_method method, uint64_t tiling)
>> >> +{
>> >> +     igt_crc_t crc;
>> >> +
>> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> >> +
>> >> +     find_modeset_params();
>> >> +
>> >> +     /* Use IGT_DRAW_MMAP_GTT on an untiled buffer as the parameter for
>> >> +      * comparison. Cache the value so we don't recompute it for every single
>> >> +      * subtest. */
>> >> +     if (!has_method_base_crc) {
>> >> +             get_method_crc(IGT_DRAW_MMAP_GTT, LOCAL_DRM_FORMAT_MOD_NONE,
>> >> +                            &method_base_crc);
>> >> +             has_method_base_crc = true;
>> >> +     }
>> >> +
>> >> +     get_method_crc(method, tiling, &crc);
>> >> +     igt_assert_crc_equal(&crc, &method_base_crc);
>> >> +}
>> >> +
>> >> +static void get_fill_crc(uint64_t tiling, igt_crc_t *crc)
>> >> +{
>> >> +     struct igt_fb fb;
>> >> +     int rc;
>> >> +
>> >> +     igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
>> >> +                   DRM_FORMAT_XRGB8888, tiling, &fb);
>> >> +
>> >> +     igt_draw_fill_fb(drm_fd, &fb, 0xFF);
>> >> +
>> >> +     rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
>> >> +                         &ms.connector_id, 1, ms.mode);
>> >> +     igt_assert(rc == 0);
>> >> +
>> >> +     igt_debug_wait_for_keypress("crc");
>> >> +     igt_pipe_crc_collect_crc(pipe_crc, crc);
>> >> +
>> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> >> +     igt_remove_fb(drm_fd, &fb);
>> >> +}
>> >> +
>> >> +static void fill_fb_subtest(void)
>> >> +{
>> >> +     int rc;
>> >> +     struct igt_fb fb;
>> >> +     igt_crc_t base_crc, crc;
>> >> +
>> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> >> +
>> >> +     find_modeset_params();
>> >> +
>> >> +     igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
>> >> +                   DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb);
>> >> +
>> >> +     igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, IGT_DRAW_MMAP_GTT,
>> >> +                      0, 0, fb.width, fb.height, 0xFF);
>> >> +
>> >> +     rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
>> >> +                         &ms.connector_id, 1, ms.mode);
>> >> +     igt_assert(rc == 0);
>> >> +
>> >> +     igt_debug_wait_for_keypress("crc");
>> >> +     igt_pipe_crc_collect_crc(pipe_crc, &base_crc);
>> >> +
>> >> +     get_fill_crc(LOCAL_DRM_FORMAT_MOD_NONE, &crc);
>> >> +     igt_assert_crc_equal(&crc, &base_crc);
>> >> +
>> >> +     get_fill_crc(LOCAL_I915_FORMAT_MOD_X_TILED, &crc);
>> >> +     igt_assert_crc_equal(&crc, &base_crc);
>> >> +
>> >> +     kmstest_unset_all_crtcs(drm_fd, drm_res);
>> >> +     igt_remove_fb(drm_fd, &fb);
>> >> +}
>> >> +
>> >> +static void setup_environment(void)
>> >> +{
>> >> +     int i;
>> >> +
>> >> +     drm_fd = drm_open_any_master();
>> >> +     igt_require(drm_fd >= 0);
>> >> +
>> >> +     drm_res = drmModeGetResources(drm_fd);
>> >> +     igt_assert(drm_res->count_connectors <= MAX_CONNECTORS);
>> >> +
>> >> +     for (i = 0; i < drm_res->count_connectors; i++)
>> >> +             drm_connectors[i] = drmModeGetConnector(drm_fd,
>> >> +                                                     drm_res->connectors[i]);
>> >> +
>> >> +     kmstest_set_vt_graphics_mode();
>> >> +
>> >> +     bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
>> >> +     igt_assert(bufmgr);
>> >> +     drm_intel_bufmgr_gem_enable_reuse(bufmgr);
>> >> +
>> >> +     pipe_crc = igt_pipe_crc_new(0, INTEL_PIPE_CRC_SOURCE_AUTO);
>> >> +}
>> >> +
>> >> +static void teardown_environment(void)
>> >> +{
>> >> +     int i;
>> >> +
>> >> +     igt_pipe_crc_free(pipe_crc);
>> >> +
>> >> +     drm_intel_bufmgr_destroy(bufmgr);
>> >> +
>> >> +     for (i = 0; i < drm_res->count_connectors; i++)
>> >> +             drmModeFreeConnector(drm_connectors[i]);
>> >> +
>> >> +     drmModeFreeResources(drm_res);
>> >> +     close(drm_fd);
>> >> +}
>> >> +
>> >> +igt_main
>> >> +{
>> >> +     enum igt_draw_method method;
>> >> +
>> >> +     igt_fixture
>> >> +             setup_environment();
>> >> +
>> >> +     for (method = 0; method < IGT_DRAW_METHOD_COUNT; method++) {
>> >> +             igt_subtest_f("draw-method-%s-untiled",
>> >> +                           igt_draw_get_method_name(method))
>> >> +                     draw_method_subtest(method, LOCAL_DRM_FORMAT_MOD_NONE);
>> >> +             igt_subtest_f("draw-method-%s-tiled",
>> >> +                           igt_draw_get_method_name(method))
>> >> +                     draw_method_subtest(method,
>> >> +                                         LOCAL_I915_FORMAT_MOD_X_TILED);
>> >> +     }
>> >> +
>> >> +     igt_subtest("fill-fb")
>> >> +             fill_fb_subtest();
>> >> +
>> >> +     igt_fixture
>> >> +             teardown_environment();
>> >> +}
>> >> --
>> >> 2.1.4
>> >>
>> >> _______________________________________________
>> >> Intel-gfx mailing list
>> >> Intel-gfx@lists.freedesktop.org
>> >> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>> >
>> > --
>> > Daniel Vetter
>> > Software Engineer, Intel Corporation
>> > http://blog.ffwll.ch
>>
>>
>>
>> --
>> Paulo Zanoni
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch



-- 
Paulo Zanoni
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 7/7] lib: add igt_draw
  2015-03-31 14:03         ` Paulo Zanoni
@ 2015-03-31 21:52           ` Paulo Zanoni
  2015-03-31 22:05             ` Chris Wilson
  0 siblings, 1 reply; 29+ messages in thread
From: Paulo Zanoni @ 2015-03-31 21:52 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

For all those IGT tests that need an easy way to draw rectangles on
buffers using different methods. Current planned users: FBC and PSR
CRC tests.

There is also a tests/kms_draw_crc program to check if the library is
sane.

v2: - Move the test from lib/tests to tests/ (Daniel).
    - Add igt_require() to filter out the swizzling/tiling methods we
      don't support (Daniel).
    - Simplify reloc handling on the BLT case (Daniel).
    - Document enum igt_draw_method (Daniel).
    - Document igt_draw_get_method_name() (Paulo).

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 lib/Makefile.sources   |   2 +
 lib/igt_draw.c         | 500 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_draw.h         |  63 +++++++
 tests/.gitignore       |   1 +
 tests/Makefile.sources |   1 +
 tests/kms_draw_crc.c   | 247 ++++++++++++++++++++++++
 6 files changed, 814 insertions(+)
 create mode 100644 lib/igt_draw.c
 create mode 100644 lib/igt_draw.h
 create mode 100644 tests/kms_draw_crc.c

The only things suggested by Daniel and not addressed are:
 - Moving the igt_debug_wait_for_keypress() calls into the CRC code. This should
   be a separate patch.
 - Support for a fallback function for when tiling/swizzling is not supported.
   Function igt_draw_fill_fb() was already there and should be enough for these
   cases, since it uses the simple GTT mmap implementation.

diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 3d93629..85dc321 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -52,6 +52,8 @@ libintel_tools_la_SOURCES = 	\
 	igt_fb.h		\
 	igt_core.c		\
 	igt_core.h		\
+	igt_draw.c		\
+	igt_draw.h		\
 	$(NULL)
 
 .PHONY: version.h.tmp
diff --git a/lib/igt_draw.c b/lib/igt_draw.c
new file mode 100644
index 0000000..2dbbe6a
--- /dev/null
+++ b/lib/igt_draw.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <sys/mman.h>
+
+#include "igt_draw.h"
+
+#include "drmtest.h"
+#include "intel_chipset.h"
+#include "igt_core.h"
+#include "igt_fb.h"
+#include "ioctl_wrappers.h"
+
+/**
+ * SECTION:igt_draw
+ * @short_description: drawing helpers for tests
+ * @title: i-g-t draw
+ * @include: igt_draw.h
+ *
+ * This library contains some functions for drawing rectangles on buffers using
+ * the many different drawing methods we have. It also contains some wrappers
+ * that make the process easier if you have the abstract objects in hand.
+ *
+ * All functions assume the buffers are in the XRGB 8:8:8 format.
+ *
+ */
+
+/* Some internal data structures to avoid having to pass tons of parameters
+ * around everything. */
+struct cmd_data {
+	drm_intel_bufmgr *bufmgr;
+	drm_intel_context *context;
+};
+
+struct buf_data {
+	uint32_t handle;
+	uint32_t size;
+	uint32_t stride;
+};
+
+struct rect {
+	int x;
+	int y;
+	int w;
+	int h;
+};
+
+/**
+ * igt_draw_get_method_name:
+ *
+ * Simple function to transform the enum into a string. Useful when naming
+ * subtests and printing debug messages.
+ */
+const char *igt_draw_get_method_name(enum igt_draw_method method)
+{
+	switch (method) {
+	case IGT_DRAW_MMAP_CPU:
+		return "mmap-cpu";
+	case IGT_DRAW_MMAP_GTT:
+		return "mmap-gtt";
+	case IGT_DRAW_PWRITE:
+		return "pwrite";
+	case IGT_DRAW_BLT:
+		return "blt";
+	case IGT_DRAW_RENDER:
+		return "render";
+	default:
+		igt_assert(false);
+	}
+}
+
+static int swizzle_addr(int addr, int swizzle)
+{
+	int bit6;
+
+	switch (swizzle) {
+	case I915_BIT_6_SWIZZLE_NONE:
+		break;
+	case I915_BIT_6_SWIZZLE_9_10:
+		bit6 = ((addr >> 6) & 1) ^ ((addr >> 9) & 1) ^
+		       ((addr >> 10) & 1);
+		addr &= ~(1 << 6);
+		addr |= (bit6 << 6);
+		break;
+	default:
+		/* If we hit this case, we need to implement support for the
+		 * appropriate swizzling method. */
+		igt_require(false);
+	}
+
+	return addr;
+}
+
+/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
+ * if you need to. */
+static int linear_x_y_to_tiled_pos(int x, int y, uint32_t stride, int swizzle)
+{
+	int x_tile_size, y_tile_size;
+	int x_tile_n, y_tile_n, x_tile_off, y_tile_off;
+	int line_size, tile_size;
+	int tile_n, tile_off;
+	int tiled_pos, tiles_per_line;
+	int bpp;
+
+	line_size = stride;
+	x_tile_size = 512;
+	y_tile_size = 8;
+	tile_size = x_tile_size * y_tile_size;
+	tiles_per_line = line_size / x_tile_size;
+	bpp = sizeof(uint32_t);
+
+	y_tile_n = y / y_tile_size;
+	y_tile_off = y % y_tile_size;
+
+	x_tile_n = (x * bpp) / x_tile_size;
+	x_tile_off = (x * bpp) % x_tile_size;
+
+	tile_n = y_tile_n * tiles_per_line + x_tile_n;
+	tile_off = y_tile_off * x_tile_size + x_tile_off;
+	tiled_pos = tile_n * tile_size + tile_off;
+
+	tiled_pos = swizzle_addr(tiled_pos, swizzle);
+
+	return tiled_pos / bpp;
+}
+
+/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
+ * if you need to. */
+static void tiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
+				    int swizzle, int *x, int *y)
+{
+	int tile_n, tile_off, tiles_per_line, line_size;
+	int x_tile_off, y_tile_off;
+	int x_tile_n, y_tile_n;
+	int x_tile_size, y_tile_size, tile_size;
+	int bpp;
+
+	tiled_pos = swizzle_addr(tiled_pos, swizzle);
+
+	line_size = stride;
+	x_tile_size = 512;
+	y_tile_size = 8;
+	tile_size = x_tile_size * y_tile_size;
+	tiles_per_line = line_size / x_tile_size;
+	bpp = sizeof(uint32_t);
+
+	tile_n = tiled_pos / tile_size;
+	tile_off = tiled_pos % tile_size;
+
+	y_tile_off = tile_off / x_tile_size;
+	x_tile_off = tile_off % x_tile_size;
+
+	x_tile_n = tile_n % tiles_per_line;
+	y_tile_n = tile_n / tiles_per_line;
+
+	*x = (x_tile_n * x_tile_size + x_tile_off) / bpp;
+	*y = y_tile_n * y_tile_size + y_tile_off;
+}
+
+static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
+			       uint32_t color)
+{
+	uint32_t *ptr;
+	int x, y, pos;
+	uint32_t tiling, swizzle;
+
+	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
+		       I915_GEM_DOMAIN_CPU);
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	/* We didn't implement suport for the older tiling methods yet. */
+	if (tiling != I915_TILING_NONE)
+		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
+
+	ptr = gem_mmap__cpu(fd, buf->handle, 0, buf->size, 0);
+	igt_assert(ptr);
+
+
+	for (y = rect->y; y < rect->y + rect->h; y++) {
+		for (x = rect->x; x < rect->x + rect->w; x++) {
+			switch (tiling) {
+			case I915_TILING_NONE:
+				pos = (y * buf->stride / sizeof(uint32_t)) + x;
+				break;
+			case I915_TILING_X:
+				pos = linear_x_y_to_tiled_pos(x, y, buf->stride,
+							      swizzle);
+				break;
+			default:
+				igt_assert(false);
+				break;
+			}
+			ptr[pos] = color;
+		}
+	}
+
+	gem_sw_finish(fd, buf->handle);
+
+	igt_assert(munmap(ptr, buf->size) == 0);
+}
+
+static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
+			       uint32_t color)
+{
+	uint32_t *ptr;
+	int x, y;
+
+	ptr = gem_mmap__gtt(fd, buf->handle, buf->size,
+			    PROT_READ | PROT_WRITE);
+	igt_assert(ptr);
+
+	for (y = rect->y; y < rect->y + rect->h; y++) {
+		int line_begin = y * buf->stride / sizeof(uint32_t);
+		for (x = rect->x; x < rect->x + rect->w; x++)
+			ptr[line_begin + x] = color;
+	}
+
+	igt_assert(munmap(ptr, buf->size) == 0);
+}
+
+static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
+				     struct rect *rect, uint32_t color)
+{
+	uint32_t tmp[rect->w];
+	int i, y, offset, bpp;
+
+	bpp = sizeof(uint32_t);
+
+	for (i = 0; i < rect->w; i++)
+		tmp[i] = color;
+
+	for (y = rect->y; y < rect->y + rect->h; y++) {
+		offset = (y * buf->stride) + (rect->x * bpp);
+		gem_write(fd, buf->handle, offset, tmp, rect->w * bpp);
+	}
+}
+
+static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
+				   struct rect *rect, uint32_t color,
+				   uint32_t swizzle)
+{
+	int i;
+	int tiled_pos, bpp, x, y;
+	uint32_t tmp[1024];
+	int tmp_used = 0, tmp_size = ARRAY_SIZE(tmp);
+	bool flush_tmp = false;
+	int tmp_start_pos = 0;
+
+	/* We didn't implement suport for the older tiling methods yet. */
+	igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
+
+	bpp = sizeof(uint32_t);
+
+	/* Instead of doing one pwrite per pixel, we try to group the maximum
+	 * amount of consecutive pixels we can in a single pwrite: that's why we
+	 * use the "tmp" variables. */
+	for (i = 0; i < tmp_size; i++)
+		tmp[i] = color;
+
+	for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += bpp) {
+		tiled_pos_to_x_y_linear(tiled_pos, buf->stride, swizzle, &x, &y);
+
+		if (x >= rect->x && x < rect->x + rect->w &&
+		    y >= rect->y && y < rect->y + rect->h) {
+			if (tmp_used == 0)
+				tmp_start_pos = tiled_pos;
+			tmp_used++;
+		} else {
+			flush_tmp = true;
+		}
+
+		if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0)) {
+			gem_write(fd, buf->handle, tmp_start_pos, tmp,
+				  tmp_used * bpp);
+			flush_tmp = false;
+			tmp_used = 0;
+		}
+	}
+}
+
+static void draw_rect_pwrite(int fd, struct buf_data *buf,
+			     struct rect *rect, uint32_t color)
+{
+	uint32_t tiling, swizzle;
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	switch (tiling) {
+	case I915_TILING_NONE:
+		draw_rect_pwrite_untiled(fd, buf, rect, color);
+		break;
+	case I915_TILING_X:
+		draw_rect_pwrite_tiled(fd, buf, rect, color, swizzle);
+		break;
+	default:
+		igt_assert(false);
+		break;
+	}
+}
+
+static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
+			  struct buf_data *buf, struct rect *rect,
+			  uint32_t color)
+{
+	drm_intel_bo *dst;
+	struct intel_batchbuffer *batch;
+	int blt_cmd_len, blt_cmd_tiling;
+	uint32_t devid = intel_get_drm_devid(fd);
+	int gen = intel_gen(devid);
+	uint32_t tiling, swizzle;
+	int pitch;
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
+	igt_assert(dst);
+
+	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
+	igt_assert(batch);
+
+	blt_cmd_len = (gen >= 8) ?  0x5 : 0x4;
+	blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
+	pitch = (tiling) ? buf->stride / 4 : buf->stride;
+
+	BEGIN_BATCH(6, 1);
+	OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
+		  XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
+	OUT_BATCH((3 << 24) | (0xF0 << 16) | pitch);
+	OUT_BATCH((rect->y << 16) | rect->x);
+	OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
+	OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
+	OUT_BATCH(color);
+	ADVANCE_BATCH();
+
+	intel_batchbuffer_flush(batch);
+	gem_sync(fd, buf->handle);
+	intel_batchbuffer_free(batch);
+}
+
+static void draw_rect_render(int fd, struct cmd_data *cmd_data,
+			     struct buf_data *buf, struct rect *rect,
+			     uint32_t color)
+{
+	drm_intel_bo *src, *dst;
+	uint32_t devid = intel_get_drm_devid(fd);
+	igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
+	struct igt_buf src_buf, dst_buf;
+	struct intel_batchbuffer *batch;
+	uint32_t tiling, swizzle;
+	struct buf_data tmp;
+
+	igt_skip_on(!rendercopy);
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	/* We create a temporary buffer and copy from it using rendercopy. */
+	tmp.size = rect->w * rect->h * sizeof(uint32_t);
+	tmp.handle = gem_create(fd, tmp.size);
+	tmp.stride = rect->w * sizeof(uint32_t);
+	draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
+			   color);
+
+	src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
+	igt_assert(src);
+	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
+	igt_assert(dst);
+
+	src_buf.bo = src;
+	src_buf.stride = tmp.stride;
+	src_buf.tiling = I915_TILING_NONE;
+	src_buf.size = tmp.size;
+	dst_buf.bo = dst;
+	dst_buf.stride = buf->stride;
+	dst_buf.tiling = tiling;
+	dst_buf.size = buf->size;
+
+	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
+	igt_assert(batch);
+
+	rendercopy(batch, cmd_data->context, &src_buf, 0, 0, rect->w, rect->h,
+		   &dst_buf, rect->x, rect->y);
+
+	gem_sync(fd, buf->handle);
+	intel_batchbuffer_free(batch);
+	gem_close(fd, tmp.handle);
+}
+
+/**
+ * igt_draw_rect:
+ * @fd: the DRM file descriptor
+ * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
+ *          IGT_DRAW_RENDER
+ * @context: the context, can be NULL if you don't want to think about it
+ * @buf_handle: the handle of the buffer where you're going to draw to
+ * @buf_size: the size of the buffer
+ * @buf_stride: the stride of the buffer
+ * @method: method you're going to use to write to the buffer
+ * @rect_x: horizontal position on the buffer where your rectangle starts
+ * @rect_y: vertical position on the buffer where your rectangle starts
+ * @rect_w: width of the rectangle
+ * @rect_h: height of the rectangle
+ * @color: color of the rectangle
+ *
+ * This function draws a colored rectangle on the destination buffer, allowing
+ * you to specify the method used to draw the rectangle. We assume 32 bit pixels
+ * with 8 bits per color.
+ */
+void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
+		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
+		   enum igt_draw_method method, int rect_x, int rect_y,
+		   int rect_w, int rect_h, uint32_t color)
+{
+	struct cmd_data cmd_data = {
+		.bufmgr = bufmgr,
+		.context = context,
+	};
+	struct buf_data buf = {
+		.handle = buf_handle,
+		.size = buf_size,
+		.stride = buf_stride,
+	};
+	struct rect rect = {
+		.x = rect_x,
+		.y = rect_y,
+		.w = rect_w,
+		.h = rect_h,
+	};
+
+	switch (method) {
+	case IGT_DRAW_MMAP_CPU:
+		draw_rect_mmap_cpu(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_MMAP_GTT:
+		draw_rect_mmap_gtt(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_PWRITE:
+		draw_rect_pwrite(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_BLT:
+		draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
+		break;
+	case IGT_DRAW_RENDER:
+		draw_rect_render(fd, &cmd_data, &buf, &rect, color);
+		break;
+	default:
+		igt_assert(false);
+		break;
+	}
+}
+
+/**
+ * igt_draw_rect_fb:
+ *
+ * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
+ * of manually providing its details. See igt_draw_rect.
+ */
+void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
+		      drm_intel_context *context, struct igt_fb *fb,
+		      enum igt_draw_method method, int rect_x, int rect_y,
+		      int rect_w, int rect_h, uint32_t color)
+{
+	igt_draw_rect(fd, bufmgr, context, fb->gem_handle, fb->size, fb->stride,
+		      method, rect_x, rect_y, rect_w, rect_h, color);
+}
+
+/**
+ * igt_draw_fill_fb:
+ * @fd: the DRM file descriptor
+ * @fb: the FB that is going to be filled
+ * @color: the color you're going to paint it
+ *
+ * This function just paints an igt_fb using the provided color. It assumes 32
+ * bit pixels with 8 bit colors.
+ */
+void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
+{
+	igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
+			 0, 0, fb->width, fb->height, color);
+}
diff --git a/lib/igt_draw.h b/lib/igt_draw.h
new file mode 100644
index 0000000..dfa9967
--- /dev/null
+++ b/lib/igt_draw.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __IGT_DRAW_H__
+#define __IGT_DRAW_H__
+
+#include <intel_bufmgr.h>
+#include "igt_fb.h"
+
+/**
+ *igt_draw_method:
+ * @IGT_DRAW_MMAP_CPU: draw using a CPU mmap.
+ * @IGT_DRAW_MMAP_GTT: draw using a GTT mmap.
+ * @IGT_DRAW_PWRITE: draw using the pwrite ioctl.
+ * @IGT_DRAW_BLT: draw using the BLT ring.
+ * @IGT_DRAW_RENDER: draw using the render ring.
+ * @IGT_DRAW_METHOD_COUNT: useful for iterating through everything.
+ */
+enum igt_draw_method {
+	IGT_DRAW_MMAP_CPU,
+	IGT_DRAW_MMAP_GTT,
+	IGT_DRAW_PWRITE,
+	IGT_DRAW_BLT,
+	IGT_DRAW_RENDER,
+	IGT_DRAW_METHOD_COUNT,
+};
+
+const char *igt_draw_get_method_name(enum igt_draw_method method);
+
+void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
+		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
+		   enum igt_draw_method method, int rect_x, int rect_y,
+		   int rect_w, int rect_h, uint32_t color);
+
+void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
+		      drm_intel_context *context, struct igt_fb *fb,
+		      enum igt_draw_method method, int rect_x, int rect_y,
+		      int rect_w, int rect_h, uint32_t color);
+
+void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color);
+
+#endif /* __IGT_DRAW_H__ */
diff --git a/tests/.gitignore b/tests/.gitignore
index 1f0e2d1..ae9de29 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -125,6 +125,7 @@ gen7_forcewake_mt
 kms_3d
 kms_addfb
 kms_cursor_crc
+kms_draw_crc
 kms_fbc_crc
 kms_fence_pin_leak
 kms_flip
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 93e05e4..b8941b0 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -69,6 +69,7 @@ TESTS_progs_M = \
 	gem_write_read_ring_switch \
 	kms_addfb \
 	kms_cursor_crc \
+	kms_draw_crc \
 	kms_fbc_crc \
 	kms_flip \
 	kms_flip_event_leak \
diff --git a/tests/kms_draw_crc.c b/tests/kms_draw_crc.c
new file mode 100644
index 0000000..1630cc2
--- /dev/null
+++ b/tests/kms_draw_crc.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+/* This program tests whether the igt_draw library actually works. */
+
+#include "drmtest.h"
+#include "igt_aux.h"
+#include "igt_draw.h"
+#include "igt_debugfs.h"
+#include "igt_fb.h"
+#include "igt_kms.h"
+
+#define MAX_CONNECTORS 32
+
+struct modeset_params {
+	uint32_t crtc_id;
+	uint32_t connector_id;
+	drmModeModeInfoPtr mode;
+};
+
+int drm_fd;
+drmModeResPtr drm_res;
+drmModeConnectorPtr drm_connectors[MAX_CONNECTORS];
+drm_intel_bufmgr *bufmgr;
+igt_pipe_crc_t *pipe_crc;
+
+bool has_method_base_crc = false;
+igt_crc_t method_base_crc;
+
+struct modeset_params ms;
+
+static void find_modeset_params(void)
+{
+	int i;
+	uint32_t connector_id = 0, crtc_id;
+	drmModeModeInfoPtr mode = NULL;
+
+	for (i = 0; i < drm_res->count_connectors; i++) {
+		drmModeConnectorPtr c = drm_connectors[i];
+
+		if (c->count_modes) {
+			connector_id = c->connector_id;
+			mode = &c->modes[0];
+			break;
+		}
+	}
+	igt_require(connector_id);
+
+	crtc_id = drm_res->crtcs[0];
+	igt_assert(crtc_id);
+	igt_assert(mode);
+
+	ms.connector_id = connector_id;
+	ms.crtc_id = crtc_id;
+	ms.mode = mode;
+
+}
+
+static void get_method_crc(enum igt_draw_method method, uint64_t tiling,
+			   igt_crc_t *crc)
+{
+	struct igt_fb fb;
+	int rc;
+
+	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
+		      DRM_FORMAT_XRGB8888, tiling, &fb);
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 0, 0, fb.width, fb.height, 0xFF);
+
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 fb.width / 4, fb.height / 4,
+			 fb.width / 2, fb.height / 2, 0xFF00);
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 fb.width / 8, fb.height / 8,
+			 fb.width / 4, fb.height / 4, 0xFF0000);
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 fb.width / 2, fb.height / 2,
+			 fb.width / 3, fb.height / 3, 0xFF00FF);
+
+	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
+			    &ms.connector_id, 1, ms.mode);
+	igt_assert(rc == 0);
+
+	igt_debug_wait_for_keypress("crc");
+	igt_pipe_crc_collect_crc(pipe_crc, crc);
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+	igt_remove_fb(drm_fd, &fb);
+}
+
+static void draw_method_subtest(enum igt_draw_method method, uint64_t tiling)
+{
+	igt_crc_t crc;
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+
+	find_modeset_params();
+
+	/* Use IGT_DRAW_MMAP_GTT on an untiled buffer as the parameter for
+	 * comparison. Cache the value so we don't recompute it for every single
+	 * subtest. */
+	if (!has_method_base_crc) {
+		get_method_crc(IGT_DRAW_MMAP_GTT, LOCAL_DRM_FORMAT_MOD_NONE,
+			       &method_base_crc);
+		has_method_base_crc = true;
+	}
+
+	get_method_crc(method, tiling, &crc);
+	igt_assert_crc_equal(&crc, &method_base_crc);
+}
+
+static void get_fill_crc(uint64_t tiling, igt_crc_t *crc)
+{
+	struct igt_fb fb;
+	int rc;
+
+	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
+		      DRM_FORMAT_XRGB8888, tiling, &fb);
+
+	igt_draw_fill_fb(drm_fd, &fb, 0xFF);
+
+	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
+			    &ms.connector_id, 1, ms.mode);
+	igt_assert(rc == 0);
+
+	igt_debug_wait_for_keypress("crc");
+	igt_pipe_crc_collect_crc(pipe_crc, crc);
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+	igt_remove_fb(drm_fd, &fb);
+}
+
+static void fill_fb_subtest(void)
+{
+	int rc;
+	struct igt_fb fb;
+	igt_crc_t base_crc, crc;
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+
+	find_modeset_params();
+
+	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
+		      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb);
+
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, IGT_DRAW_MMAP_GTT,
+			 0, 0, fb.width, fb.height, 0xFF);
+
+	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
+			    &ms.connector_id, 1, ms.mode);
+	igt_assert(rc == 0);
+
+	igt_debug_wait_for_keypress("crc");
+	igt_pipe_crc_collect_crc(pipe_crc, &base_crc);
+
+	get_fill_crc(LOCAL_DRM_FORMAT_MOD_NONE, &crc);
+	igt_assert_crc_equal(&crc, &base_crc);
+
+	get_fill_crc(LOCAL_I915_FORMAT_MOD_X_TILED, &crc);
+	igt_assert_crc_equal(&crc, &base_crc);
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+	igt_remove_fb(drm_fd, &fb);
+}
+
+static void setup_environment(void)
+{
+	int i;
+
+	drm_fd = drm_open_any_master();
+	igt_require(drm_fd >= 0);
+
+	drm_res = drmModeGetResources(drm_fd);
+	igt_assert(drm_res->count_connectors <= MAX_CONNECTORS);
+
+	for (i = 0; i < drm_res->count_connectors; i++)
+		drm_connectors[i] = drmModeGetConnector(drm_fd,
+							drm_res->connectors[i]);
+
+	kmstest_set_vt_graphics_mode();
+
+	bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
+	igt_assert(bufmgr);
+	drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+	pipe_crc = igt_pipe_crc_new(0, INTEL_PIPE_CRC_SOURCE_AUTO);
+}
+
+static void teardown_environment(void)
+{
+	int i;
+
+	igt_pipe_crc_free(pipe_crc);
+
+	drm_intel_bufmgr_destroy(bufmgr);
+
+	for (i = 0; i < drm_res->count_connectors; i++)
+		drmModeFreeConnector(drm_connectors[i]);
+
+	drmModeFreeResources(drm_res);
+	close(drm_fd);
+}
+
+igt_main
+{
+	enum igt_draw_method method;
+
+	igt_fixture
+		setup_environment();
+
+	for (method = 0; method < IGT_DRAW_METHOD_COUNT; method++) {
+		igt_subtest_f("draw-method-%s-untiled",
+			      igt_draw_get_method_name(method))
+			draw_method_subtest(method, LOCAL_DRM_FORMAT_MOD_NONE);
+		igt_subtest_f("draw-method-%s-tiled",
+			      igt_draw_get_method_name(method))
+			draw_method_subtest(method,
+					    LOCAL_I915_FORMAT_MOD_X_TILED);
+	}
+
+	igt_subtest("fill-fb")
+		fill_fb_subtest();
+
+	igt_fixture
+		teardown_environment();
+}
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-03-31 21:52           ` Paulo Zanoni
@ 2015-03-31 22:05             ` Chris Wilson
  2015-04-01 22:08               ` Paulo Zanoni
  0 siblings, 1 reply; 29+ messages in thread
From: Chris Wilson @ 2015-03-31 22:05 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: intel-gfx, Paulo Zanoni

On Tue, Mar 31, 2015 at 06:52:08PM -0300, Paulo Zanoni wrote:
> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
> 
> For all those IGT tests that need an easy way to draw rectangles on
> buffers using different methods. Current planned users: FBC and PSR
> CRC tests.
> 
> There is also a tests/kms_draw_crc program to check if the library is
> sane.
> 
> v2: - Move the test from lib/tests to tests/ (Daniel).
>     - Add igt_require() to filter out the swizzling/tiling methods we
>       don't support (Daniel).
>     - Simplify reloc handling on the BLT case (Daniel).
>     - Document enum igt_draw_method (Daniel).
>     - Document igt_draw_get_method_name() (Paulo).

You are already missing one draw path (mmap wc), adding the extra swizzle
modes for anything but bit17 is trivial, the BLT code is an opencoded
intel_copy_bo and what is with all the sync? Moving everything into the
GTT write domain (i.e. manually doing cache flushes) would seem to
nullify the point of using the GPU in the first place.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-03-31 22:05             ` Chris Wilson
@ 2015-04-01 22:08               ` Paulo Zanoni
  2015-04-01 22:22                 ` Chris Wilson
  0 siblings, 1 reply; 29+ messages in thread
From: Paulo Zanoni @ 2015-04-01 22:08 UTC (permalink / raw)
  To: Chris Wilson, Paulo Zanoni, Intel Graphics Development, Paulo Zanoni

2015-03-31 19:05 GMT-03:00 Chris Wilson <chris@chris-wilson.co.uk>:
> On Tue, Mar 31, 2015 at 06:52:08PM -0300, Paulo Zanoni wrote:
>> From: Paulo Zanoni <paulo.r.zanoni@intel.com>
>>
>> For all those IGT tests that need an easy way to draw rectangles on
>> buffers using different methods. Current planned users: FBC and PSR
>> CRC tests.
>>
>> There is also a tests/kms_draw_crc program to check if the library is
>> sane.
>>
>> v2: - Move the test from lib/tests to tests/ (Daniel).
>>     - Add igt_require() to filter out the swizzling/tiling methods we
>>       don't support (Daniel).
>>     - Simplify reloc handling on the BLT case (Daniel).
>>     - Document enum igt_draw_method (Daniel).
>>     - Document igt_draw_get_method_name() (Paulo).
>
> You are already missing one draw path (mmap wc),

Oh, new stuff! Done.

> adding the extra swizzle
> modes for anything but bit17 is trivial,

Done.

> the BLT code is an opencoded
> intel_copy_bo

No, we do BLT fills, not copies. On the render side I used rendercopy
just because I still don't know how to do a "render fill".

> and what is with all the sync? Moving everything into the
> GTT write domain (i.e. manually doing cache flushes) would seem to
> nullify the point of using the GPU in the first place.

The idea was to just be as simple as possible for the callers, but I
can remove the gem_sync()s and leave it to the callers. There's also a
little explanation on patch 2: I used this lib for some FBC tests, so
the syncs would allow us to not wait so much for the retire work
handler. But Daniel/Ville had also suggested a test without the sync,
so I guess I would have removed the sync from the library anyway when
implementing the test.

Thanks for the review!

> -Chris
>
> --
> Chris Wilson, Intel Open Source Technology Centre



-- 
Paulo Zanoni
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-01 22:08               ` Paulo Zanoni
@ 2015-04-01 22:22                 ` Chris Wilson
  2015-04-01 22:33                   ` Paulo Zanoni
  0 siblings, 1 reply; 29+ messages in thread
From: Chris Wilson @ 2015-04-01 22:22 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development, Paulo Zanoni

On Wed, Apr 01, 2015 at 07:08:18PM -0300, Paulo Zanoni wrote:
> 2015-03-31 19:05 GMT-03:00 Chris Wilson <chris@chris-wilson.co.uk>:
> > the BLT code is an opencoded
> > intel_copy_bo
> 
> No, we do BLT fills, not copies. On the render side I used rendercopy
> just because I still don't know how to do a "render fill".

Ojjjjh, my mistake then. We certainly could do with an intel_bo_fill()
routine as we use XY_COLOR_BLT in quite a few places now.

> > and what is with all the sync? Moving everything into the
> > GTT write domain (i.e. manually doing cache flushes) would seem to
> > nullify the point of using the GPU in the first place.
> 
> The idea was to just be as simple as possible for the callers, but I
> can remove the gem_sync()s and leave it to the callers. There's also a
> little explanation on patch 2: I used this lib for some FBC tests, so
> the syncs would allow us to not wait so much for the retire work
> handler.

Which retire work handler? Not the requests one surely? 
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-01 22:22                 ` Chris Wilson
@ 2015-04-01 22:33                   ` Paulo Zanoni
  2015-04-01 22:40                     ` Paulo Zanoni
  2015-04-01 23:03                     ` Chris Wilson
  0 siblings, 2 replies; 29+ messages in thread
From: Paulo Zanoni @ 2015-04-01 22:33 UTC (permalink / raw)
  To: Chris Wilson, Paulo Zanoni, Intel Graphics Development, Paulo Zanoni

2015-04-01 19:22 GMT-03:00 Chris Wilson <chris@chris-wilson.co.uk>:
> On Wed, Apr 01, 2015 at 07:08:18PM -0300, Paulo Zanoni wrote:
>> 2015-03-31 19:05 GMT-03:00 Chris Wilson <chris@chris-wilson.co.uk>:
>> > the BLT code is an opencoded
>> > intel_copy_bo
>>
>> No, we do BLT fills, not copies. On the render side I used rendercopy
>> just because I still don't know how to do a "render fill".
>
> Ojjjjh, my mistake then. We certainly could do with an intel_bo_fill()
> routine as we use XY_COLOR_BLT in quite a few places now.

I just added this to my TODO list. Some of the current XY_COLOR_BLT
users will become users of igt_draw, so the duplication will be
reduced a little bit. Later we can create intel_bo_fill and make
igt_draw call it.

>
>> > and what is with all the sync? Moving everything into the
>> > GTT write domain (i.e. manually doing cache flushes) would seem to
>> > nullify the point of using the GPU in the first place.
>>
>> The idea was to just be as simple as possible for the callers, but I
>> can remove the gem_sync()s and leave it to the callers. There's also a
>> little explanation on patch 2: I used this lib for some FBC tests, so
>> the syncs would allow us to not wait so much for the retire work
>> handler.
>
> Which retire work handler? Not the requests one surely?

i915_gem_retire_work_handler()

Now that we use the frontbuffer tracking mechanism, when we use the
BLT, FBC gets disabled (by intel_fb_obj_invalidate(), called by
i915_gem_execbuffer2()). But if we don't gem_sync(), FBC only gets
reenabled after i915_gem_retire_work_handler() happens and calls
intel_frontbuffer_flush(). While having FBC disabled for a long time
is not a bug, the gem_sync() helps reducing the
many-undreds-of-milliseconds waits.

>
> --
> Chris Wilson, Intel Open Source Technology Centre



-- 
Paulo Zanoni
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 7/7] lib: add igt_draw
  2015-04-01 22:33                   ` Paulo Zanoni
@ 2015-04-01 22:40                     ` Paulo Zanoni
  2015-04-01 23:15                       ` Chris Wilson
  2015-04-01 23:03                     ` Chris Wilson
  1 sibling, 1 reply; 29+ messages in thread
From: Paulo Zanoni @ 2015-04-01 22:40 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

For all those IGT tests that need an easy way to draw rectangles on
buffers using different methods. Current planned users: FBC and PSR
CRC tests.

There is also a tests/kms_draw_crc program to check if the library is
sane.

v2: - Move the test from lib/tests to tests/ (Daniel).
    - Add igt_require() to filter out the swizzling/tiling methods we
      don't support (Daniel).
    - Simplify reloc handling on the BLT case (Daniel).
    - Document enum igt_draw_method (Daniel).
    - Document igt_draw_get_method_name() (Paulo).
v3: - Add IGT_DRAW_MMAP_WC (Chris).
    - Implement the other trivial swizzling methods (Chris).
    - Remove the gem_sync() calls (Chris).

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 lib/Makefile.sources   |   2 +
 lib/igt_draw.c         | 562 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_draw.h         |  65 ++++++
 tests/.gitignore       |   1 +
 tests/Makefile.sources |   1 +
 tests/kms_draw_crc.c   | 247 ++++++++++++++++++++++
 6 files changed, 878 insertions(+)
 create mode 100644 lib/igt_draw.c
 create mode 100644 lib/igt_draw.h
 create mode 100644 tests/kms_draw_crc.c

diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 3d93629..85dc321 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -52,6 +52,8 @@ libintel_tools_la_SOURCES = 	\
 	igt_fb.h		\
 	igt_core.c		\
 	igt_core.h		\
+	igt_draw.c		\
+	igt_draw.h		\
 	$(NULL)
 
 .PHONY: version.h.tmp
diff --git a/lib/igt_draw.c b/lib/igt_draw.c
new file mode 100644
index 0000000..14e470f
--- /dev/null
+++ b/lib/igt_draw.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <sys/mman.h>
+
+#include "igt_draw.h"
+
+#include "drmtest.h"
+#include "intel_chipset.h"
+#include "igt_core.h"
+#include "igt_fb.h"
+#include "ioctl_wrappers.h"
+
+/**
+ * SECTION:igt_draw
+ * @short_description: drawing helpers for tests
+ * @title: i-g-t draw
+ * @include: igt_draw.h
+ *
+ * This library contains some functions for drawing rectangles on buffers using
+ * the many different drawing methods we have. It also contains some wrappers
+ * that make the process easier if you have the abstract objects in hand.
+ *
+ * All functions assume the buffers are in the XRGB 8:8:8 format.
+ *
+ */
+
+/* Some internal data structures to avoid having to pass tons of parameters
+ * around everything. */
+struct cmd_data {
+	drm_intel_bufmgr *bufmgr;
+	drm_intel_context *context;
+};
+
+struct buf_data {
+	uint32_t handle;
+	uint32_t size;
+	uint32_t stride;
+};
+
+struct rect {
+	int x;
+	int y;
+	int w;
+	int h;
+};
+
+/**
+ * igt_draw_get_method_name:
+ *
+ * Simple function to transform the enum into a string. Useful when naming
+ * subtests and printing debug messages.
+ */
+const char *igt_draw_get_method_name(enum igt_draw_method method)
+{
+	switch (method) {
+	case IGT_DRAW_MMAP_CPU:
+		return "mmap-cpu";
+	case IGT_DRAW_MMAP_GTT:
+		return "mmap-gtt";
+	case IGT_DRAW_MMAP_WC:
+		return "mmap-wc";
+	case IGT_DRAW_PWRITE:
+		return "pwrite";
+	case IGT_DRAW_BLT:
+		return "blt";
+	case IGT_DRAW_RENDER:
+		return "render";
+	default:
+		igt_assert(false);
+	}
+}
+
+#define BIT(num, bit) ((num >> bit) & 1)
+
+static int swizzle_addr(int addr, int swizzle)
+{
+	int bit6;
+
+	switch (swizzle) {
+	case I915_BIT_6_SWIZZLE_NONE:
+		bit6 = BIT(addr, 6);
+		break;
+	case I915_BIT_6_SWIZZLE_9:
+		bit6 = BIT(addr, 6) ^ BIT(addr, 9);
+		break;
+	case I915_BIT_6_SWIZZLE_9_10:
+		bit6 = BIT(addr, 6) ^ BIT(addr, 9) ^ BIT(addr, 10);
+		break;
+	case I915_BIT_6_SWIZZLE_9_11:
+		bit6 = BIT(addr, 6) ^ BIT(addr, 9) ^ BIT(addr, 11);
+		break;
+	case I915_BIT_6_SWIZZLE_9_10_11:
+		bit6 = BIT(addr, 6) ^ BIT(addr, 9) ^ BIT(addr, 10) ^
+		       BIT(addr, 11);
+		break;
+	case I915_BIT_6_SWIZZLE_UNKNOWN:
+	case I915_BIT_6_SWIZZLE_9_17:
+	case I915_BIT_6_SWIZZLE_9_10_17:
+	default:
+		/* If we hit this case, we need to implement support for the
+		 * appropriate swizzling method. */
+		igt_require(false);
+		break;
+	}
+
+	addr &= ~(1 << 6);
+	addr |= (bit6 << 6);
+	return addr;
+}
+
+/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
+ * if you need to. */
+static int linear_x_y_to_tiled_pos(int x, int y, uint32_t stride, int swizzle)
+{
+	int x_tile_size, y_tile_size;
+	int x_tile_n, y_tile_n, x_tile_off, y_tile_off;
+	int line_size, tile_size;
+	int tile_n, tile_off;
+	int tiled_pos, tiles_per_line;
+	int bpp;
+
+	line_size = stride;
+	x_tile_size = 512;
+	y_tile_size = 8;
+	tile_size = x_tile_size * y_tile_size;
+	tiles_per_line = line_size / x_tile_size;
+	bpp = sizeof(uint32_t);
+
+	y_tile_n = y / y_tile_size;
+	y_tile_off = y % y_tile_size;
+
+	x_tile_n = (x * bpp) / x_tile_size;
+	x_tile_off = (x * bpp) % x_tile_size;
+
+	tile_n = y_tile_n * tiles_per_line + x_tile_n;
+	tile_off = y_tile_off * x_tile_size + x_tile_off;
+	tiled_pos = tile_n * tile_size + tile_off;
+
+	tiled_pos = swizzle_addr(tiled_pos, swizzle);
+
+	return tiled_pos / bpp;
+}
+
+/* It's all in "pixel coordinates", so make sure you multiply/divide by the bpp
+ * if you need to. */
+static void tiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
+				    int swizzle, int *x, int *y)
+{
+	int tile_n, tile_off, tiles_per_line, line_size;
+	int x_tile_off, y_tile_off;
+	int x_tile_n, y_tile_n;
+	int x_tile_size, y_tile_size, tile_size;
+	int bpp;
+
+	tiled_pos = swizzle_addr(tiled_pos, swizzle);
+
+	line_size = stride;
+	x_tile_size = 512;
+	y_tile_size = 8;
+	tile_size = x_tile_size * y_tile_size;
+	tiles_per_line = line_size / x_tile_size;
+	bpp = sizeof(uint32_t);
+
+	tile_n = tiled_pos / tile_size;
+	tile_off = tiled_pos % tile_size;
+
+	y_tile_off = tile_off / x_tile_size;
+	x_tile_off = tile_off % x_tile_size;
+
+	x_tile_n = tile_n % tiles_per_line;
+	y_tile_n = tile_n / tiles_per_line;
+
+	*x = (x_tile_n * x_tile_size + x_tile_off) / bpp;
+	*y = y_tile_n * y_tile_size + y_tile_off;
+}
+
+static void draw_rect_ptr_linear(uint32_t *ptr, uint32_t stride,
+				  struct rect *rect, uint32_t color)
+{
+	int x, y, line_begin;
+
+	for (y = rect->y; y < rect->y + rect->h; y++) {
+		line_begin = y * stride / sizeof(uint32_t);
+		for (x = rect->x; x < rect->x + rect->w; x++)
+			ptr[line_begin + x] = color;
+	}
+
+}
+
+static void draw_rect_ptr_tiled(uint32_t *ptr, uint32_t stride, int swizzle,
+				 struct rect *rect, uint32_t color)
+{
+	int x, y, pos;
+
+	for (y = rect->y; y < rect->y + rect->h; y++) {
+		for (x = rect->x; x < rect->x + rect->w; x++) {
+			pos = linear_x_y_to_tiled_pos(x, y, stride, swizzle);
+			ptr[pos] = color;
+		}
+	}
+}
+
+static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
+			       uint32_t color)
+{
+	uint32_t *ptr;
+	uint32_t tiling, swizzle;
+
+	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
+		       I915_GEM_DOMAIN_CPU);
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	/* We didn't implement suport for the older tiling methods yet. */
+	if (tiling != I915_TILING_NONE)
+		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
+
+	ptr = gem_mmap__cpu(fd, buf->handle, 0, buf->size, 0);
+	igt_assert(ptr);
+
+	switch (tiling) {
+	case I915_TILING_NONE:
+		draw_rect_ptr_linear(ptr, buf->stride, rect, color);
+		break;
+	case I915_TILING_X:
+		draw_rect_ptr_tiled(ptr, buf->stride, swizzle, rect, color);
+		break;
+	default:
+		igt_assert(false);
+		break;
+	}
+
+	gem_sw_finish(fd, buf->handle);
+
+	igt_assert(munmap(ptr, buf->size) == 0);
+}
+
+static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
+			       uint32_t color)
+{
+	uint32_t *ptr;
+
+	ptr = gem_mmap__gtt(fd, buf->handle, buf->size, PROT_READ | PROT_WRITE);
+	igt_assert(ptr);
+
+	draw_rect_ptr_linear(ptr, buf->stride, rect, color);
+
+	igt_assert(munmap(ptr, buf->size) == 0);
+}
+
+static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
+			      uint32_t color)
+{
+	uint32_t *ptr;
+	uint32_t tiling, swizzle;
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	/* We didn't implement suport for the older tiling methods yet. */
+	if (tiling != I915_TILING_NONE)
+		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
+
+	ptr = gem_mmap__wc(fd, buf->handle, 0, buf->size,
+			   PROT_READ | PROT_WRITE);
+	igt_assert(ptr);
+
+	switch (tiling) {
+	case I915_TILING_NONE:
+		draw_rect_ptr_linear(ptr, buf->stride, rect, color);
+		break;
+	case I915_TILING_X:
+		draw_rect_ptr_tiled(ptr, buf->stride, swizzle, rect, color);
+		break;
+	default:
+		igt_assert(false);
+		break;
+	}
+
+	igt_assert(munmap(ptr, buf->size) == 0);
+}
+
+static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
+				     struct rect *rect, uint32_t color)
+{
+	uint32_t tmp[rect->w];
+	int i, y, offset, bpp;
+
+	bpp = sizeof(uint32_t);
+
+	for (i = 0; i < rect->w; i++)
+		tmp[i] = color;
+
+	for (y = rect->y; y < rect->y + rect->h; y++) {
+		offset = (y * buf->stride) + (rect->x * bpp);
+		gem_write(fd, buf->handle, offset, tmp, rect->w * bpp);
+	}
+}
+
+static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
+				   struct rect *rect, uint32_t color,
+				   uint32_t swizzle)
+{
+	int i;
+	int tiled_pos, bpp, x, y;
+	uint32_t tmp[1024];
+	int tmp_used = 0, tmp_size = ARRAY_SIZE(tmp);
+	bool flush_tmp = false;
+	int tmp_start_pos = 0;
+
+	/* We didn't implement suport for the older tiling methods yet. */
+	igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
+
+	bpp = sizeof(uint32_t);
+
+	/* Instead of doing one pwrite per pixel, we try to group the maximum
+	 * amount of consecutive pixels we can in a single pwrite: that's why we
+	 * use the "tmp" variables. */
+	for (i = 0; i < tmp_size; i++)
+		tmp[i] = color;
+
+	for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += bpp) {
+		tiled_pos_to_x_y_linear(tiled_pos, buf->stride, swizzle, &x, &y);
+
+		if (x >= rect->x && x < rect->x + rect->w &&
+		    y >= rect->y && y < rect->y + rect->h) {
+			if (tmp_used == 0)
+				tmp_start_pos = tiled_pos;
+			tmp_used++;
+		} else {
+			flush_tmp = true;
+		}
+
+		if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0)) {
+			gem_write(fd, buf->handle, tmp_start_pos, tmp,
+				  tmp_used * bpp);
+			flush_tmp = false;
+			tmp_used = 0;
+		}
+	}
+}
+
+static void draw_rect_pwrite(int fd, struct buf_data *buf,
+			     struct rect *rect, uint32_t color)
+{
+	uint32_t tiling, swizzle;
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	switch (tiling) {
+	case I915_TILING_NONE:
+		draw_rect_pwrite_untiled(fd, buf, rect, color);
+		break;
+	case I915_TILING_X:
+		draw_rect_pwrite_tiled(fd, buf, rect, color, swizzle);
+		break;
+	default:
+		igt_assert(false);
+		break;
+	}
+}
+
+static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
+			  struct buf_data *buf, struct rect *rect,
+			  uint32_t color)
+{
+	drm_intel_bo *dst;
+	struct intel_batchbuffer *batch;
+	int blt_cmd_len, blt_cmd_tiling;
+	uint32_t devid = intel_get_drm_devid(fd);
+	int gen = intel_gen(devid);
+	uint32_t tiling, swizzle;
+	int pitch;
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
+	igt_assert(dst);
+
+	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
+	igt_assert(batch);
+
+	blt_cmd_len = (gen >= 8) ?  0x5 : 0x4;
+	blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
+	pitch = (tiling) ? buf->stride / 4 : buf->stride;
+
+	BEGIN_BATCH(6, 1);
+	OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
+		  XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
+	OUT_BATCH((3 << 24) | (0xF0 << 16) | pitch);
+	OUT_BATCH((rect->y << 16) | rect->x);
+	OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
+	OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
+	OUT_BATCH(color);
+	ADVANCE_BATCH();
+
+	intel_batchbuffer_flush(batch);
+	intel_batchbuffer_free(batch);
+}
+
+static void draw_rect_render(int fd, struct cmd_data *cmd_data,
+			     struct buf_data *buf, struct rect *rect,
+			     uint32_t color)
+{
+	drm_intel_bo *src, *dst;
+	uint32_t devid = intel_get_drm_devid(fd);
+	igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
+	struct igt_buf src_buf, dst_buf;
+	struct intel_batchbuffer *batch;
+	uint32_t tiling, swizzle;
+	struct buf_data tmp;
+
+	igt_skip_on(!rendercopy);
+
+	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
+
+	/* We create a temporary buffer and copy from it using rendercopy. */
+	tmp.size = rect->w * rect->h * sizeof(uint32_t);
+	tmp.handle = gem_create(fd, tmp.size);
+	tmp.stride = rect->w * sizeof(uint32_t);
+	draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
+			   color);
+
+	src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
+	igt_assert(src);
+	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
+	igt_assert(dst);
+
+	src_buf.bo = src;
+	src_buf.stride = tmp.stride;
+	src_buf.tiling = I915_TILING_NONE;
+	src_buf.size = tmp.size;
+	dst_buf.bo = dst;
+	dst_buf.stride = buf->stride;
+	dst_buf.tiling = tiling;
+	dst_buf.size = buf->size;
+
+	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
+	igt_assert(batch);
+
+	rendercopy(batch, cmd_data->context, &src_buf, 0, 0, rect->w, rect->h,
+		   &dst_buf, rect->x, rect->y);
+
+	intel_batchbuffer_free(batch);
+	gem_close(fd, tmp.handle);
+}
+
+/**
+ * igt_draw_rect:
+ * @fd: the DRM file descriptor
+ * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
+ *          IGT_DRAW_RENDER
+ * @context: the context, can be NULL if you don't want to think about it
+ * @buf_handle: the handle of the buffer where you're going to draw to
+ * @buf_size: the size of the buffer
+ * @buf_stride: the stride of the buffer
+ * @method: method you're going to use to write to the buffer
+ * @rect_x: horizontal position on the buffer where your rectangle starts
+ * @rect_y: vertical position on the buffer where your rectangle starts
+ * @rect_w: width of the rectangle
+ * @rect_h: height of the rectangle
+ * @color: color of the rectangle
+ *
+ * This function draws a colored rectangle on the destination buffer, allowing
+ * you to specify the method used to draw the rectangle. We assume 32 bit pixels
+ * with 8 bits per color.
+ */
+void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
+		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
+		   enum igt_draw_method method, int rect_x, int rect_y,
+		   int rect_w, int rect_h, uint32_t color)
+{
+	struct cmd_data cmd_data = {
+		.bufmgr = bufmgr,
+		.context = context,
+	};
+	struct buf_data buf = {
+		.handle = buf_handle,
+		.size = buf_size,
+		.stride = buf_stride,
+	};
+	struct rect rect = {
+		.x = rect_x,
+		.y = rect_y,
+		.w = rect_w,
+		.h = rect_h,
+	};
+
+	switch (method) {
+	case IGT_DRAW_MMAP_CPU:
+		draw_rect_mmap_cpu(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_MMAP_GTT:
+		draw_rect_mmap_gtt(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_MMAP_WC:
+		draw_rect_mmap_wc(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_PWRITE:
+		draw_rect_pwrite(fd, &buf, &rect, color);
+		break;
+	case IGT_DRAW_BLT:
+		draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
+		break;
+	case IGT_DRAW_RENDER:
+		draw_rect_render(fd, &cmd_data, &buf, &rect, color);
+		break;
+	default:
+		igt_assert(false);
+		break;
+	}
+}
+
+/**
+ * igt_draw_rect_fb:
+ *
+ * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
+ * of manually providing its details. See igt_draw_rect.
+ */
+void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
+		      drm_intel_context *context, struct igt_fb *fb,
+		      enum igt_draw_method method, int rect_x, int rect_y,
+		      int rect_w, int rect_h, uint32_t color)
+{
+	igt_draw_rect(fd, bufmgr, context, fb->gem_handle, fb->size, fb->stride,
+		      method, rect_x, rect_y, rect_w, rect_h, color);
+}
+
+/**
+ * igt_draw_fill_fb:
+ * @fd: the DRM file descriptor
+ * @fb: the FB that is going to be filled
+ * @color: the color you're going to paint it
+ *
+ * This function just paints an igt_fb using the provided color. It assumes 32
+ * bit pixels with 8 bit colors.
+ */
+void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
+{
+	igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
+			 0, 0, fb->width, fb->height, color);
+}
diff --git a/lib/igt_draw.h b/lib/igt_draw.h
new file mode 100644
index 0000000..61ffad5
--- /dev/null
+++ b/lib/igt_draw.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef __IGT_DRAW_H__
+#define __IGT_DRAW_H__
+
+#include <intel_bufmgr.h>
+#include "igt_fb.h"
+
+/**
+ *igt_draw_method:
+ * @IGT_DRAW_MMAP_CPU: draw using a CPU mmap.
+ * @IGT_DRAW_MMAP_GTT: draw using a GTT mmap.
+ * @IGT-DRAW_MMAP_WC: draw using the WC mmap.
+ * @IGT_DRAW_PWRITE: draw using the pwrite ioctl.
+ * @IGT_DRAW_BLT: draw using the BLT ring.
+ * @IGT_DRAW_RENDER: draw using the render ring.
+ * @IGT_DRAW_METHOD_COUNT: useful for iterating through everything.
+ */
+enum igt_draw_method {
+	IGT_DRAW_MMAP_CPU,
+	IGT_DRAW_MMAP_GTT,
+	IGT_DRAW_MMAP_WC,
+	IGT_DRAW_PWRITE,
+	IGT_DRAW_BLT,
+	IGT_DRAW_RENDER,
+	IGT_DRAW_METHOD_COUNT,
+};
+
+const char *igt_draw_get_method_name(enum igt_draw_method method);
+
+void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
+		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
+		   enum igt_draw_method method, int rect_x, int rect_y,
+		   int rect_w, int rect_h, uint32_t color);
+
+void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
+		      drm_intel_context *context, struct igt_fb *fb,
+		      enum igt_draw_method method, int rect_x, int rect_y,
+		      int rect_w, int rect_h, uint32_t color);
+
+void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color);
+
+#endif /* __IGT_DRAW_H__ */
diff --git a/tests/.gitignore b/tests/.gitignore
index 1f0e2d1..ae9de29 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -125,6 +125,7 @@ gen7_forcewake_mt
 kms_3d
 kms_addfb
 kms_cursor_crc
+kms_draw_crc
 kms_fbc_crc
 kms_fence_pin_leak
 kms_flip
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 93e05e4..b8941b0 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -69,6 +69,7 @@ TESTS_progs_M = \
 	gem_write_read_ring_switch \
 	kms_addfb \
 	kms_cursor_crc \
+	kms_draw_crc \
 	kms_fbc_crc \
 	kms_flip \
 	kms_flip_event_leak \
diff --git a/tests/kms_draw_crc.c b/tests/kms_draw_crc.c
new file mode 100644
index 0000000..1630cc2
--- /dev/null
+++ b/tests/kms_draw_crc.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+/* This program tests whether the igt_draw library actually works. */
+
+#include "drmtest.h"
+#include "igt_aux.h"
+#include "igt_draw.h"
+#include "igt_debugfs.h"
+#include "igt_fb.h"
+#include "igt_kms.h"
+
+#define MAX_CONNECTORS 32
+
+struct modeset_params {
+	uint32_t crtc_id;
+	uint32_t connector_id;
+	drmModeModeInfoPtr mode;
+};
+
+int drm_fd;
+drmModeResPtr drm_res;
+drmModeConnectorPtr drm_connectors[MAX_CONNECTORS];
+drm_intel_bufmgr *bufmgr;
+igt_pipe_crc_t *pipe_crc;
+
+bool has_method_base_crc = false;
+igt_crc_t method_base_crc;
+
+struct modeset_params ms;
+
+static void find_modeset_params(void)
+{
+	int i;
+	uint32_t connector_id = 0, crtc_id;
+	drmModeModeInfoPtr mode = NULL;
+
+	for (i = 0; i < drm_res->count_connectors; i++) {
+		drmModeConnectorPtr c = drm_connectors[i];
+
+		if (c->count_modes) {
+			connector_id = c->connector_id;
+			mode = &c->modes[0];
+			break;
+		}
+	}
+	igt_require(connector_id);
+
+	crtc_id = drm_res->crtcs[0];
+	igt_assert(crtc_id);
+	igt_assert(mode);
+
+	ms.connector_id = connector_id;
+	ms.crtc_id = crtc_id;
+	ms.mode = mode;
+
+}
+
+static void get_method_crc(enum igt_draw_method method, uint64_t tiling,
+			   igt_crc_t *crc)
+{
+	struct igt_fb fb;
+	int rc;
+
+	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
+		      DRM_FORMAT_XRGB8888, tiling, &fb);
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 0, 0, fb.width, fb.height, 0xFF);
+
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 fb.width / 4, fb.height / 4,
+			 fb.width / 2, fb.height / 2, 0xFF00);
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 fb.width / 8, fb.height / 8,
+			 fb.width / 4, fb.height / 4, 0xFF0000);
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, method,
+			 fb.width / 2, fb.height / 2,
+			 fb.width / 3, fb.height / 3, 0xFF00FF);
+
+	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
+			    &ms.connector_id, 1, ms.mode);
+	igt_assert(rc == 0);
+
+	igt_debug_wait_for_keypress("crc");
+	igt_pipe_crc_collect_crc(pipe_crc, crc);
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+	igt_remove_fb(drm_fd, &fb);
+}
+
+static void draw_method_subtest(enum igt_draw_method method, uint64_t tiling)
+{
+	igt_crc_t crc;
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+
+	find_modeset_params();
+
+	/* Use IGT_DRAW_MMAP_GTT on an untiled buffer as the parameter for
+	 * comparison. Cache the value so we don't recompute it for every single
+	 * subtest. */
+	if (!has_method_base_crc) {
+		get_method_crc(IGT_DRAW_MMAP_GTT, LOCAL_DRM_FORMAT_MOD_NONE,
+			       &method_base_crc);
+		has_method_base_crc = true;
+	}
+
+	get_method_crc(method, tiling, &crc);
+	igt_assert_crc_equal(&crc, &method_base_crc);
+}
+
+static void get_fill_crc(uint64_t tiling, igt_crc_t *crc)
+{
+	struct igt_fb fb;
+	int rc;
+
+	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
+		      DRM_FORMAT_XRGB8888, tiling, &fb);
+
+	igt_draw_fill_fb(drm_fd, &fb, 0xFF);
+
+	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
+			    &ms.connector_id, 1, ms.mode);
+	igt_assert(rc == 0);
+
+	igt_debug_wait_for_keypress("crc");
+	igt_pipe_crc_collect_crc(pipe_crc, crc);
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+	igt_remove_fb(drm_fd, &fb);
+}
+
+static void fill_fb_subtest(void)
+{
+	int rc;
+	struct igt_fb fb;
+	igt_crc_t base_crc, crc;
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+
+	find_modeset_params();
+
+	igt_create_fb(drm_fd, ms.mode->hdisplay, ms.mode->vdisplay,
+		      DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb);
+
+	igt_draw_rect_fb(drm_fd, bufmgr, NULL, &fb, IGT_DRAW_MMAP_GTT,
+			 0, 0, fb.width, fb.height, 0xFF);
+
+	rc = drmModeSetCrtc(drm_fd, ms.crtc_id, fb.fb_id, 0, 0,
+			    &ms.connector_id, 1, ms.mode);
+	igt_assert(rc == 0);
+
+	igt_debug_wait_for_keypress("crc");
+	igt_pipe_crc_collect_crc(pipe_crc, &base_crc);
+
+	get_fill_crc(LOCAL_DRM_FORMAT_MOD_NONE, &crc);
+	igt_assert_crc_equal(&crc, &base_crc);
+
+	get_fill_crc(LOCAL_I915_FORMAT_MOD_X_TILED, &crc);
+	igt_assert_crc_equal(&crc, &base_crc);
+
+	kmstest_unset_all_crtcs(drm_fd, drm_res);
+	igt_remove_fb(drm_fd, &fb);
+}
+
+static void setup_environment(void)
+{
+	int i;
+
+	drm_fd = drm_open_any_master();
+	igt_require(drm_fd >= 0);
+
+	drm_res = drmModeGetResources(drm_fd);
+	igt_assert(drm_res->count_connectors <= MAX_CONNECTORS);
+
+	for (i = 0; i < drm_res->count_connectors; i++)
+		drm_connectors[i] = drmModeGetConnector(drm_fd,
+							drm_res->connectors[i]);
+
+	kmstest_set_vt_graphics_mode();
+
+	bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
+	igt_assert(bufmgr);
+	drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+	pipe_crc = igt_pipe_crc_new(0, INTEL_PIPE_CRC_SOURCE_AUTO);
+}
+
+static void teardown_environment(void)
+{
+	int i;
+
+	igt_pipe_crc_free(pipe_crc);
+
+	drm_intel_bufmgr_destroy(bufmgr);
+
+	for (i = 0; i < drm_res->count_connectors; i++)
+		drmModeFreeConnector(drm_connectors[i]);
+
+	drmModeFreeResources(drm_res);
+	close(drm_fd);
+}
+
+igt_main
+{
+	enum igt_draw_method method;
+
+	igt_fixture
+		setup_environment();
+
+	for (method = 0; method < IGT_DRAW_METHOD_COUNT; method++) {
+		igt_subtest_f("draw-method-%s-untiled",
+			      igt_draw_get_method_name(method))
+			draw_method_subtest(method, LOCAL_DRM_FORMAT_MOD_NONE);
+		igt_subtest_f("draw-method-%s-tiled",
+			      igt_draw_get_method_name(method))
+			draw_method_subtest(method,
+					    LOCAL_I915_FORMAT_MOD_X_TILED);
+	}
+
+	igt_subtest("fill-fb")
+		fill_fb_subtest();
+
+	igt_fixture
+		teardown_environment();
+}
-- 
2.1.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-01 22:33                   ` Paulo Zanoni
  2015-04-01 22:40                     ` Paulo Zanoni
@ 2015-04-01 23:03                     ` Chris Wilson
  1 sibling, 0 replies; 29+ messages in thread
From: Chris Wilson @ 2015-04-01 23:03 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development, Paulo Zanoni

On Wed, Apr 01, 2015 at 07:33:15PM -0300, Paulo Zanoni wrote:
> 2015-04-01 19:22 GMT-03:00 Chris Wilson <chris@chris-wilson.co.uk>:
> > On Wed, Apr 01, 2015 at 07:08:18PM -0300, Paulo Zanoni wrote:
> >> 2015-03-31 19:05 GMT-03:00 Chris Wilson <chris@chris-wilson.co.uk>:
> >> > the BLT code is an opencoded
> >> > intel_copy_bo
> >>
> >> No, we do BLT fills, not copies. On the render side I used rendercopy
> >> just because I still don't know how to do a "render fill".
> >
> > Ojjjjh, my mistake then. We certainly could do with an intel_bo_fill()
> > routine as we use XY_COLOR_BLT in quite a few places now.
> 
> I just added this to my TODO list. Some of the current XY_COLOR_BLT
> users will become users of igt_draw, so the duplication will be
> reduced a little bit. Later we can create intel_bo_fill and make
> igt_draw call it.
> 
> >
> >> > and what is with all the sync? Moving everything into the
> >> > GTT write domain (i.e. manually doing cache flushes) would seem to
> >> > nullify the point of using the GPU in the first place.
> >>
> >> The idea was to just be as simple as possible for the callers, but I
> >> can remove the gem_sync()s and leave it to the callers. There's also a
> >> little explanation on patch 2: I used this lib for some FBC tests, so
> >> the syncs would allow us to not wait so much for the retire work
> >> handler.
> >
> > Which retire work handler? Not the requests one surely?
> 
> i915_gem_retire_work_handler()
> 
> Now that we use the frontbuffer tracking mechanism, when we use the
> BLT, FBC gets disabled (by intel_fb_obj_invalidate(), called by
> i915_gem_execbuffer2()). But if we don't gem_sync(), FBC only gets
> reenabled after i915_gem_retire_work_handler() happens and calls
> intel_frontbuffer_flush(). While having FBC disabled for a long time
> is not a bug, the gem_sync() helps reducing the
> many-undreds-of-milliseconds waits.

Hmm. Bad news, that side-effect of gem_sync() won't happen in future.
You would need to call gem_sync() on the framebuffer to trigger the
flush, but that itself would then set the framebuffer to the GTT write
domain which should then invalidate the FBC again. To flush without
invalidate you want set_domain(scanout, read=GTT, write=0).
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-01 22:40                     ` Paulo Zanoni
@ 2015-04-01 23:15                       ` Chris Wilson
  2015-04-01 23:17                         ` Chris Wilson
  2015-04-07  8:10                         ` Daniel Vetter
  0 siblings, 2 replies; 29+ messages in thread
From: Chris Wilson @ 2015-04-01 23:15 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: intel-gfx, Paulo Zanoni

On Wed, Apr 01, 2015 at 07:40:59PM -0300, Paulo Zanoni wrote:
> +static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
> +			      uint32_t color)
> +{
> +	uint32_t *ptr;
> +	uint32_t tiling, swizzle;
> +
> +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> +
> +	/* We didn't implement suport for the older tiling methods yet. */
> +	if (tiling != I915_TILING_NONE)
> +		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);

But you now do! You need something like:

static void get_tiling_and_swizzle(int fd,
				   struct buf_data *buf,
				   int *tiling, int *swizzle)
{
	struct local_i915_gem_get_tiling_v2 {
		uint32_t handle;
		uint32_t tiling_mode;
		uint32_t swizzle_mode;
		uint32_t phys_swizzle_mode;
	} tiling;
#define LOCAL_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct local_i915_gem_get_tiling_v2)

	memset(&tiling, 0, sizeof(tiling));
	tiling.handle = buf->handle;
	do_ioctl(fd, LOCAL_IOCTL_I915_GEM_GET_TILING, &tiling);
	igt_require(tiling.phys_swizzle == tiling.swizzle_mode ||
		    intel_gen(intel_get_drm_devid(fd)) >= 5); /* old kernel? */

	*tiling = tiling.tilling_mode;
	*swizzle = tiling.swizzle_mode;
}

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-01 23:15                       ` Chris Wilson
@ 2015-04-01 23:17                         ` Chris Wilson
  2015-04-07  8:10                         ` Daniel Vetter
  1 sibling, 0 replies; 29+ messages in thread
From: Chris Wilson @ 2015-04-01 23:17 UTC (permalink / raw)
  To: Paulo Zanoni, intel-gfx, Paulo Zanoni

On Thu, Apr 02, 2015 at 12:15:13AM +0100, Chris Wilson wrote:
> On Wed, Apr 01, 2015 at 07:40:59PM -0300, Paulo Zanoni wrote:
> > +static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
> > +			      uint32_t color)
> > +{
> > +	uint32_t *ptr;
> > +	uint32_t tiling, swizzle;
> > +
> > +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> > +
> > +	/* We didn't implement suport for the older tiling methods yet. */
> > +	if (tiling != I915_TILING_NONE)
> > +		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
> 
> But you now do!

Oh, with the exception of gen2. You need to adjust the tilesize
constants there.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-01 23:15                       ` Chris Wilson
  2015-04-01 23:17                         ` Chris Wilson
@ 2015-04-07  8:10                         ` Daniel Vetter
  2015-04-07  8:36                           ` Chris Wilson
  1 sibling, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2015-04-07  8:10 UTC (permalink / raw)
  To: Chris Wilson, Paulo Zanoni, intel-gfx, Paulo Zanoni

On Thu, Apr 02, 2015 at 12:15:13AM +0100, Chris Wilson wrote:
> On Wed, Apr 01, 2015 at 07:40:59PM -0300, Paulo Zanoni wrote:
> > +static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
> > +			      uint32_t color)
> > +{
> > +	uint32_t *ptr;
> > +	uint32_t tiling, swizzle;
> > +
> > +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> > +
> > +	/* We didn't implement suport for the older tiling methods yet. */
> > +	if (tiling != I915_TILING_NONE)
> > +		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
> 
> But you now do! You need something like:

The problem is that the kernel hides bit17 swizzling. I chatted with Paulo
on irc about this and we decided just ignore them all is the simplest
approach.
-Daniel

> 
> static void get_tiling_and_swizzle(int fd,
> 				   struct buf_data *buf,
> 				   int *tiling, int *swizzle)
> {
> 	struct local_i915_gem_get_tiling_v2 {
> 		uint32_t handle;
> 		uint32_t tiling_mode;
> 		uint32_t swizzle_mode;
> 		uint32_t phys_swizzle_mode;
> 	} tiling;
> #define LOCAL_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct local_i915_gem_get_tiling_v2)
> 
> 	memset(&tiling, 0, sizeof(tiling));
> 	tiling.handle = buf->handle;
> 	do_ioctl(fd, LOCAL_IOCTL_I915_GEM_GET_TILING, &tiling);
> 	igt_require(tiling.phys_swizzle == tiling.swizzle_mode ||
> 		    intel_gen(intel_get_drm_devid(fd)) >= 5); /* old kernel? */
> 
> 	*tiling = tiling.tilling_mode;
> 	*swizzle = tiling.swizzle_mode;
> }
> 
> -- 
> Chris Wilson, Intel Open Source Technology Centre
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-07  8:10                         ` Daniel Vetter
@ 2015-04-07  8:36                           ` Chris Wilson
  2015-04-07  9:07                             ` Daniel Vetter
  0 siblings, 1 reply; 29+ messages in thread
From: Chris Wilson @ 2015-04-07  8:36 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, Paulo Zanoni

On Tue, Apr 07, 2015 at 10:10:25AM +0200, Daniel Vetter wrote:
> On Thu, Apr 02, 2015 at 12:15:13AM +0100, Chris Wilson wrote:
> > On Wed, Apr 01, 2015 at 07:40:59PM -0300, Paulo Zanoni wrote:
> > > +static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
> > > +			      uint32_t color)
> > > +{
> > > +	uint32_t *ptr;
> > > +	uint32_t tiling, swizzle;
> > > +
> > > +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> > > +
> > > +	/* We didn't implement suport for the older tiling methods yet. */
> > > +	if (tiling != I915_TILING_NONE)
> > > +		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
> > 
> > But you now do! You need something like:
> 
> The problem is that the kernel hides bit17 swizzling. I chatted with Paulo
> on irc about this and we decided just ignore them all is the simplest
> approach.

Urm, that was the whole point of GET_TILING v2. That small function is
all you need to determine when bit17 is in effect and then you get to
reuse all the direct CPU methods (as they are also used by userspace)
for earlier gen.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-07  8:36                           ` Chris Wilson
@ 2015-04-07  9:07                             ` Daniel Vetter
  2015-04-07 10:12                               ` Chris Wilson
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2015-04-07  9:07 UTC (permalink / raw)
  To: Chris Wilson, Daniel Vetter, Paulo Zanoni, intel-gfx, Paulo Zanoni

On Tue, Apr 07, 2015 at 09:36:37AM +0100, Chris Wilson wrote:
> On Tue, Apr 07, 2015 at 10:10:25AM +0200, Daniel Vetter wrote:
> > On Thu, Apr 02, 2015 at 12:15:13AM +0100, Chris Wilson wrote:
> > > On Wed, Apr 01, 2015 at 07:40:59PM -0300, Paulo Zanoni wrote:
> > > > +static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
> > > > +			      uint32_t color)
> > > > +{
> > > > +	uint32_t *ptr;
> > > > +	uint32_t tiling, swizzle;
> > > > +
> > > > +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> > > > +
> > > > +	/* We didn't implement suport for the older tiling methods yet. */
> > > > +	if (tiling != I915_TILING_NONE)
> > > > +		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
> > > 
> > > But you now do! You need something like:
> > 
> > The problem is that the kernel hides bit17 swizzling. I chatted with Paulo
> > on irc about this and we decided just ignore them all is the simplest
> > approach.
> 
> Urm, that was the whole point of GET_TILING v2. That small function is
> all you need to determine when bit17 is in effect and then you get to
> reuse all the direct CPU methods (as they are also used by userspace)
> for earlier gen.

Oh right completely forgot that we've added this. But imo can be added on
top once we need it (it's not just gen2 but also some gen3 which need
different tile dimensions).
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-07  9:07                             ` Daniel Vetter
@ 2015-04-07 10:12                               ` Chris Wilson
  2015-04-07 13:44                                 ` Daniel Vetter
  0 siblings, 1 reply; 29+ messages in thread
From: Chris Wilson @ 2015-04-07 10:12 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, Paulo Zanoni

On Tue, Apr 07, 2015 at 11:07:07AM +0200, Daniel Vetter wrote:
> On Tue, Apr 07, 2015 at 09:36:37AM +0100, Chris Wilson wrote:
> > On Tue, Apr 07, 2015 at 10:10:25AM +0200, Daniel Vetter wrote:
> > > On Thu, Apr 02, 2015 at 12:15:13AM +0100, Chris Wilson wrote:
> > > > On Wed, Apr 01, 2015 at 07:40:59PM -0300, Paulo Zanoni wrote:
> > > > > +static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
> > > > > +			      uint32_t color)
> > > > > +{
> > > > > +	uint32_t *ptr;
> > > > > +	uint32_t tiling, swizzle;
> > > > > +
> > > > > +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> > > > > +
> > > > > +	/* We didn't implement suport for the older tiling methods yet. */
> > > > > +	if (tiling != I915_TILING_NONE)
> > > > > +		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
> > > > 
> > > > But you now do! You need something like:
> > > 
> > > The problem is that the kernel hides bit17 swizzling. I chatted with Paulo
> > > on irc about this and we decided just ignore them all is the simplest
> > > approach.
> > 
> > Urm, that was the whole point of GET_TILING v2. That small function is
> > all you need to determine when bit17 is in effect and then you get to
> > reuse all the direct CPU methods (as they are also used by userspace)
> > for earlier gen.
> 
> Oh right completely forgot that we've added this. But imo can be added on
> top once we need it (it's not just gen2 but also some gen3 which need
> different tile dimensions).

Tile size is 2048 for gen2 only right. Tile width is the same for all
gen3 for tiling X (and gen2), but tiling Y width depends on subgen.
Right?

Just need to check because I have code that depends on this...
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-07 10:12                               ` Chris Wilson
@ 2015-04-07 13:44                                 ` Daniel Vetter
  2015-05-05 21:30                                   ` Paulo Zanoni
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2015-04-07 13:44 UTC (permalink / raw)
  To: Chris Wilson, Daniel Vetter, Paulo Zanoni, intel-gfx, Paulo Zanoni

On Tue, Apr 07, 2015 at 11:12:09AM +0100, Chris Wilson wrote:
> On Tue, Apr 07, 2015 at 11:07:07AM +0200, Daniel Vetter wrote:
> > On Tue, Apr 07, 2015 at 09:36:37AM +0100, Chris Wilson wrote:
> > > On Tue, Apr 07, 2015 at 10:10:25AM +0200, Daniel Vetter wrote:
> > > > On Thu, Apr 02, 2015 at 12:15:13AM +0100, Chris Wilson wrote:
> > > > > On Wed, Apr 01, 2015 at 07:40:59PM -0300, Paulo Zanoni wrote:
> > > > > > +static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
> > > > > > +			      uint32_t color)
> > > > > > +{
> > > > > > +	uint32_t *ptr;
> > > > > > +	uint32_t tiling, swizzle;
> > > > > > +
> > > > > > +	gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> > > > > > +
> > > > > > +	/* We didn't implement suport for the older tiling methods yet. */
> > > > > > +	if (tiling != I915_TILING_NONE)
> > > > > > +		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
> > > > > 
> > > > > But you now do! You need something like:
> > > > 
> > > > The problem is that the kernel hides bit17 swizzling. I chatted with Paulo
> > > > on irc about this and we decided just ignore them all is the simplest
> > > > approach.
> > > 
> > > Urm, that was the whole point of GET_TILING v2. That small function is
> > > all you need to determine when bit17 is in effect and then you get to
> > > reuse all the direct CPU methods (as they are also used by userspace)
> > > for earlier gen.
> > 
> > Oh right completely forgot that we've added this. But imo can be added on
> > top once we need it (it's not just gen2 but also some gen3 which need
> > different tile dimensions).
> 
> Tile size is 2048 for gen2 only right. Tile width is the same for all
> gen3 for tiling X (and gen2), but tiling Y width depends on subgen.
> Right?
> 
> Just need to check because I have code that depends on this...

Oh right thought about Y tiling which changes on gen3. X tiling matches
your description afaik - I consider gem_tiled_pread the authoritative
source for this stuff.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-04-07 13:44                                 ` Daniel Vetter
@ 2015-05-05 21:30                                   ` Paulo Zanoni
  2015-05-06  9:00                                     ` Daniel Vetter
  0 siblings, 1 reply; 29+ messages in thread
From: Paulo Zanoni @ 2015-05-05 21:30 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel Graphics Development, Paulo Zanoni

2015-04-07 10:44 GMT-03:00 Daniel Vetter <daniel@ffwll.ch>:
> On Tue, Apr 07, 2015 at 11:12:09AM +0100, Chris Wilson wrote:
>> On Tue, Apr 07, 2015 at 11:07:07AM +0200, Daniel Vetter wrote:
>> > On Tue, Apr 07, 2015 at 09:36:37AM +0100, Chris Wilson wrote:
>> > > On Tue, Apr 07, 2015 at 10:10:25AM +0200, Daniel Vetter wrote:
>> > > > On Thu, Apr 02, 2015 at 12:15:13AM +0100, Chris Wilson wrote:
>> > > > > On Wed, Apr 01, 2015 at 07:40:59PM -0300, Paulo Zanoni wrote:
>> > > > > > +static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
>> > > > > > +                         uint32_t color)
>> > > > > > +{
>> > > > > > +   uint32_t *ptr;
>> > > > > > +   uint32_t tiling, swizzle;
>> > > > > > +
>> > > > > > +   gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
>> > > > > > +
>> > > > > > +   /* We didn't implement suport for the older tiling methods yet. */
>> > > > > > +   if (tiling != I915_TILING_NONE)
>> > > > > > +           igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
>> > > > >
>> > > > > But you now do! You need something like:
>> > > >
>> > > > The problem is that the kernel hides bit17 swizzling. I chatted with Paulo
>> > > > on irc about this and we decided just ignore them all is the simplest
>> > > > approach.
>> > >
>> > > Urm, that was the whole point of GET_TILING v2. That small function is
>> > > all you need to determine when bit17 is in effect and then you get to
>> > > reuse all the direct CPU methods (as they are also used by userspace)
>> > > for earlier gen.
>> >
>> > Oh right completely forgot that we've added this. But imo can be added on
>> > top once we need it (it's not just gen2 but also some gen3 which need
>> > different tile dimensions).
>>
>> Tile size is 2048 for gen2 only right. Tile width is the same for all
>> gen3 for tiling X (and gen2), but tiling Y width depends on subgen.
>> Right?
>>
>> Just need to check because I have code that depends on this...
>
> Oh right thought about Y tiling which changes on gen3. X tiling matches
> your description afaik - I consider gem_tiled_pread the authoritative
> source for this stuff.

Ok, so after all this discussion, what is the conclusion here? What is
required before we can merge the patch?

Notice that with this patch we still won't have anybody using the
library (except for the test added by the patch), and all the users I
plan to add are gen5+. Also, I created VIZ-5495 to make sure we create
intel_bo_fill() at some point (and, when we do it, I suggest we just
use the implementation from igt_draw.c).

I really think the improvements discussed here can be done after we
merge the patch because the it's not breaking anything, AFAICS. So,
can I push this? Also, after the code is on igt, it will probably be
easier to discuss the possible improvements since we'll be able to
send patches.

Thanks for the reviews,
Paulo

> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch



-- 
Paulo Zanoni
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 7/7] lib: add igt_draw
  2015-05-05 21:30                                   ` Paulo Zanoni
@ 2015-05-06  9:00                                     ` Daniel Vetter
  0 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2015-05-06  9:00 UTC (permalink / raw)
  To: Paulo Zanoni; +Cc: Intel Graphics Development, Paulo Zanoni

On Tue, May 05, 2015 at 06:30:50PM -0300, Paulo Zanoni wrote:
> 2015-04-07 10:44 GMT-03:00 Daniel Vetter <daniel@ffwll.ch>:
> > On Tue, Apr 07, 2015 at 11:12:09AM +0100, Chris Wilson wrote:
> >> On Tue, Apr 07, 2015 at 11:07:07AM +0200, Daniel Vetter wrote:
> >> > On Tue, Apr 07, 2015 at 09:36:37AM +0100, Chris Wilson wrote:
> >> > > On Tue, Apr 07, 2015 at 10:10:25AM +0200, Daniel Vetter wrote:
> >> > > > On Thu, Apr 02, 2015 at 12:15:13AM +0100, Chris Wilson wrote:
> >> > > > > On Wed, Apr 01, 2015 at 07:40:59PM -0300, Paulo Zanoni wrote:
> >> > > > > > +static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
> >> > > > > > +                         uint32_t color)
> >> > > > > > +{
> >> > > > > > +   uint32_t *ptr;
> >> > > > > > +   uint32_t tiling, swizzle;
> >> > > > > > +
> >> > > > > > +   gem_get_tiling(fd, buf->handle, &tiling, &swizzle);
> >> > > > > > +
> >> > > > > > +   /* We didn't implement suport for the older tiling methods yet. */
> >> > > > > > +   if (tiling != I915_TILING_NONE)
> >> > > > > > +           igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
> >> > > > >
> >> > > > > But you now do! You need something like:
> >> > > >
> >> > > > The problem is that the kernel hides bit17 swizzling. I chatted with Paulo
> >> > > > on irc about this and we decided just ignore them all is the simplest
> >> > > > approach.
> >> > >
> >> > > Urm, that was the whole point of GET_TILING v2. That small function is
> >> > > all you need to determine when bit17 is in effect and then you get to
> >> > > reuse all the direct CPU methods (as they are also used by userspace)
> >> > > for earlier gen.
> >> >
> >> > Oh right completely forgot that we've added this. But imo can be added on
> >> > top once we need it (it's not just gen2 but also some gen3 which need
> >> > different tile dimensions).
> >>
> >> Tile size is 2048 for gen2 only right. Tile width is the same for all
> >> gen3 for tiling X (and gen2), but tiling Y width depends on subgen.
> >> Right?
> >>
> >> Just need to check because I have code that depends on this...
> >
> > Oh right thought about Y tiling which changes on gen3. X tiling matches
> > your description afaik - I consider gem_tiled_pread the authoritative
> > source for this stuff.
> 
> Ok, so after all this discussion, what is the conclusion here? What is
> required before we can merge the patch?
> 
> Notice that with this patch we still won't have anybody using the
> library (except for the test added by the patch), and all the users I
> plan to add are gen5+. Also, I created VIZ-5495 to make sure we create
> intel_bo_fill() at some point (and, when we do it, I suggest we just
> use the implementation from igt_draw.c).
> 
> I really think the improvements discussed here can be done after we
> merge the patch because the it's not breaking anything, AFAICS. So,
> can I push this? Also, after the code is on igt, it will probably be
> easier to discuss the possible improvements since we'll be able to
> send patches.

I guess you could capture the discussion here in a TODO comment in
igt_draw? But yeah I thought we've discussed this on irc and agreed that
moving ahead is ok, and that extensions can be done later on.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2015-05-06  8:58 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-25 21:50 [PATCH 1/7] lib: add igt_wait() Paulo Zanoni
2015-03-25 21:50 ` [PATCH 2/7] tests/kms_fb_crc: call gem_sync() instead of gem_bo_busy() Paulo Zanoni
2015-03-26 10:06   ` Daniel Vetter
2015-03-25 21:50 ` [PATCH 3/7] tests/kms_fbc_crc: add wait_for_fbc_enabled() Paulo Zanoni
2015-03-26 10:07   ` Daniel Vetter
2015-03-25 21:50 ` [PATCH 4/7] tests/kms_fbc_crc: also gem_sync() on exec_nop() Paulo Zanoni
2015-03-25 21:50 ` [PATCH 5/7] tests/kms_fbc_crc: use igt_pipe_crc_collect_crc() Paulo Zanoni
2015-03-25 21:50 ` [PATCH 6/7] tests/kms_fbc_crc: remove redundant information from data_t Paulo Zanoni
2015-03-25 21:50 ` [PATCH 7/7] lib: add igt_draw Paulo Zanoni
2015-03-26 10:19   ` Daniel Vetter
2015-03-30 19:45     ` Paulo Zanoni
2015-03-31 13:07       ` Daniel Vetter
2015-03-31 14:03         ` Paulo Zanoni
2015-03-31 21:52           ` Paulo Zanoni
2015-03-31 22:05             ` Chris Wilson
2015-04-01 22:08               ` Paulo Zanoni
2015-04-01 22:22                 ` Chris Wilson
2015-04-01 22:33                   ` Paulo Zanoni
2015-04-01 22:40                     ` Paulo Zanoni
2015-04-01 23:15                       ` Chris Wilson
2015-04-01 23:17                         ` Chris Wilson
2015-04-07  8:10                         ` Daniel Vetter
2015-04-07  8:36                           ` Chris Wilson
2015-04-07  9:07                             ` Daniel Vetter
2015-04-07 10:12                               ` Chris Wilson
2015-04-07 13:44                                 ` Daniel Vetter
2015-05-05 21:30                                   ` Paulo Zanoni
2015-05-06  9:00                                     ` Daniel Vetter
2015-04-01 23:03                     ` Chris Wilson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.